7f6cfc17f93e0b0335301f510b42629a68df644c
[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.3 2002/03/22 13:31:18 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 %lx %s %s", ADD_SUBNET, random(),
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 %*x "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   if(seen_request(c->buffer))
92     return 0;
93  
94   /* Check if the owner of the new subnet is in the connection list */
95
96   owner = lookup_node(name);
97
98   if(!owner)
99     {
100       owner = new_node();
101       owner->name = xstrdup(name);
102       node_add(owner);
103     }
104
105   /* Check if we already know this subnet */
106   
107   if(lookup_subnet(owner, s))
108     {
109       free_subnet(s);
110       return 0;
111     }
112
113   /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
114
115   if(owner == myself)
116   {
117     if(debug_lvl >= DEBUG_PROTOCOL)
118       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "ADD_SUBNET", c->name, c->hostname);
119     s->owner = myself;
120     send_del_subnet(c, s);
121     return 0;
122   }
123
124   /* If everything is correct, add the subnet to the list of the owner */
125
126   subnet_add(owner, s);
127
128   /* Tell the rest */
129   
130   for(node = connection_tree->head; node; node = node->next)
131     {
132       other = (connection_t *)node->data;
133       if(other->status.active && other != c)
134         send_request(other, "%s", c->buffer);
135     }
136 cp
137   return 0;
138 }
139
140 int send_del_subnet(connection_t *c, subnet_t *s)
141 {
142   int x;
143   char *netstr;
144 cp
145   netstr = net2str(s);
146   x = send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr);
147   free(netstr);
148 cp
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   connection_t *other;
158   subnet_t *s, *find;
159   avl_node_t *node;
160 cp
161   if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, name, subnetstr) != 2)
162     {
163       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name, c->hostname);
164       return -1;
165     }
166
167   /* Check if owner name is a valid */
168
169   if(check_id(name))
170     {
171       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name, 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   if(!(owner = lookup_node(name)))
178     {
179       if(debug_lvl >= DEBUG_PROTOCOL)
180         syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
181              "DEL_SUBNET", c->name, c->hostname, name);
182       return 0;
183     }
184
185   /* Check if subnet string is valid */
186
187   if(!(s = str2net(subnetstr)))
188     {
189       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name, c->hostname, _("invalid subnet string"));
190       return -1;
191     }
192
193   if(seen_request(c->buffer))
194     return 0;
195
196   /* If everything is correct, delete the subnet from the list of the owner */
197
198   s->owner = owner;
199
200   find = lookup_subnet(owner, s);
201   
202   free_subnet(s);
203
204   if(!find)
205     {
206       if(debug_lvl >= DEBUG_PROTOCOL)
207         syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"),
208              "DEL_SUBNET", c->name, c->hostname, name);
209       return 0;
210     }
211   
212   /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */
213   
214   if(owner == myself)
215   {
216     if(debug_lvl >= DEBUG_PROTOCOL)
217       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_SUBNET", c->name, c->hostname);
218     send_add_subnet(c, find);
219     return 0;
220   }
221
222   /* Tell the rest */
223   
224   for(node = connection_tree->head; node; node = node->next)
225     {
226       other = (connection_t *)node->data;
227       if(other->status.active && other != c)
228         send_request(other, "%s", c->buffer);
229     }
230
231   /* Finally, delete it. */
232
233   subnet_del(owner, find);
234
235 cp
236   return 0;
237 }