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