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