b426a8e9b7c1b6a67c258f43f21886ebe54a7e5d
[tinc] / src / protocol_subnet.c
1 /*
2     protocol_subnet.c -- handle the meta-protocol, subnets
3     Copyright (C) 1999-2002 Ivo Timmermans <ivo@o2w.nl>,
4                   2000-2002 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.9 2002/09/09 22:33:13 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <syslog.h>
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <errno.h>
31
32 #include <utils.h>
33 #include <xalloc.h>
34 #include <avl_tree.h>
35
36 #include "conf.h"
37 #include "net.h"
38 #include "netutl.h"
39 #include "protocol.h"
40 #include "meta.h"
41 #include "connection.h"
42 #include "node.h"
43
44 #include "system.h"
45
46 int send_add_subnet(connection_t *c, subnet_t *subnet)
47 {
48         int x;
49         char *netstr;
50
51         cp();
52
53         x = send_request(c, "%d %lx %s %s", ADD_SUBNET, random(),
54                                          subnet->owner->name, netstr = net2str(subnet));
55
56         free(netstr);
57
58         return x;
59 }
60
61 int add_subnet_h(connection_t *c)
62 {
63         char subnetstr[MAX_STRING_SIZE];
64         char name[MAX_STRING_SIZE];
65         node_t *owner;
66         subnet_t *s;
67
68         cp();
69
70         if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
71                 syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name,
72                            c->hostname);
73                 return -1;
74         }
75
76         /* Check if owner name is a valid */
77
78         if(check_id(name)) {
79                 syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
80                            c->hostname, _("invalid name"));
81                 return -1;
82         }
83
84         /* Check if subnet string is valid */
85
86         s = str2net(subnetstr);
87
88         if(!s) {
89                 syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
90                            c->hostname, _("invalid subnet string"));
91                 return -1;
92         }
93
94         if(seen_request(c->buffer))
95                 return 0;
96
97         /* Check if the owner of the new subnet is in the connection list */
98
99         owner = lookup_node(name);
100
101         if(!owner) {
102                 owner = new_node();
103                 owner->name = xstrdup(name);
104                 node_add(owner);
105         }
106
107         /* Check if we already know this subnet */
108
109         if(lookup_subnet(owner, s)) {
110                 free_subnet(s);
111                 return 0;
112         }
113
114         /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
115
116         if(owner == myself) {
117                 if(debug_lvl >= DEBUG_PROTOCOL)
118                         syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
119                                    "ADD_SUBNET", c->name, c->hostname);
120                 s->owner = myself;
121                 send_del_subnet(c, s);
122                 return 0;
123         }
124
125         /* If everything is correct, add the subnet to the list of the owner */
126
127         subnet_add(owner, s);
128
129         /* Tell the rest */
130
131         forward_request(c);
132
133         return 0;
134 }
135
136 int send_del_subnet(connection_t *c, subnet_t *s)
137 {
138         int x;
139         char *netstr;
140
141         cp();
142
143         netstr = net2str(s);
144
145         x = send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr);
146
147         free(netstr);
148
149         return x;
150 }
151
152 int del_subnet_h(connection_t *c)
153 {
154         char subnetstr[MAX_STRING_SIZE];
155         char name[MAX_STRING_SIZE];
156         node_t *owner;
157         subnet_t *s, *find;
158
159         cp();
160
161         if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
162                 syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name,
163                            c->hostname);
164                 return -1;
165         }
166
167         /* Check if owner name is a valid */
168
169         if(check_id(name)) {
170                 syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
171                            c->hostname, _("invalid name"));
172                 return -1;
173         }
174
175         /* Check if the owner of the new subnet is in the connection list */
176
177         owner = lookup_node(name);
178
179         if(!owner) {
180                 if(debug_lvl >= DEBUG_PROTOCOL)
181                         syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
182                                    "DEL_SUBNET", c->name, c->hostname, name);
183                 return 0;
184         }
185
186         /* Check if subnet string is valid */
187
188         s = str2net(subnetstr);
189
190         if(!s) {
191                 syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
192                            c->hostname, _("invalid subnet string"));
193                 return -1;
194         }
195
196         if(seen_request(c->buffer))
197                 return 0;
198
199         /* If everything is correct, delete the subnet from the list of the owner */
200
201         s->owner = owner;
202
203         find = lookup_subnet(owner, s);
204
205         free_subnet(s);
206
207         if(!find) {
208                 if(debug_lvl >= DEBUG_PROTOCOL)
209                         syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"),
210                                    "DEL_SUBNET", c->name, c->hostname, name);
211                 return 0;
212         }
213
214         /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */
215
216         if(owner == myself) {
217                 if(debug_lvl >= DEBUG_PROTOCOL)
218                         syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
219                                    "DEL_SUBNET", c->name, c->hostname);
220                 send_add_subnet(c, find);
221                 return 0;
222         }
223
224         /* Tell the rest */
225
226         forward_request(c);
227
228         /* Finally, delete it. */
229
230         subnet_del(owner, find);
231
232         return 0;
233 }