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