ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/conf/connect.c
Revision: 801
Committed: Wed Aug 30 16:54:25 2006 UTC (19 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 13180 byte(s)
Log Message:
+ only filename changes

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * connect.c: Defines the connect{} block of ircd.conf.
4 *
5 * Copyright (C) 2006 by the Hybrid Development Team.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "conf/conf.h"
27 #include "client.h"
28 #include "numeric.h"
29 #include "send.h"
30 #include "server.h"
31
32 dlink_list connect_confs = {0};
33
34 static dlink_node *hreset;
35 static struct ConnectConf tmpconn = {0};
36
37 // TODO: These should be modularised like acb_types
38 static const struct FlagMapping {
39 const char *name;
40 unsigned int flag;
41 } flag_mappings[] = {
42 {"compressed", LINK_COMPRESSED},
43 {"cryptlink", LINK_CRYPTLINK},
44 {"encrypted", LINK_CRYPTPWD},
45 {"autoconn", LINK_AUTOCONN},
46 {"burst_away", LINK_BURSTAWAY},
47 {"topicburst", LINK_TOPICBURST},
48 {NULL, 0}
49 };
50
51 /*
52 * free_interior()
53 *
54 * Frees all memory allocated by a connect entry,
55 * except the ConnectConf struct itself.
56 *
57 * inputs: pointer to the conf
58 * output: none
59 */
60 static void
61 free_interior(struct ConnectConf *conf)
62 {
63 MyFree(conf->name);
64 MyFree(conf->host);
65 MyFree(conf->allow_host);
66 MyFree(conf->send_password);
67 MyFree(conf->accept_password);
68 MyFree(conf->fakename);
69
70 if (conf->class_ptr)
71 unref_class(conf->class_ptr);
72
73 while (conf->hub_list.head)
74 {
75 dlink_node *ptr = conf->hub_list.head;
76 MyFree(ptr->data);
77 dlinkDelete(ptr, &conf->hub_list);
78 free_dlink_node(ptr);
79 }
80
81 while (conf->leaf_list.head)
82 {
83 dlink_node *ptr = conf->leaf_list.head;
84 MyFree(ptr->data);
85 dlinkDelete(ptr, &conf->leaf_list);
86 free_dlink_node(ptr);
87 }
88
89 #ifdef HAVE_LIBCRYPTO
90 if (conf->rsa_public_key)
91 RSA_free(conf->rsa_public_key);
92 #endif
93 }
94
95 static void
96 clear_temp(void)
97 {
98 free_interior(&tmpconn);
99 memset(&tmpconn, 0, sizeof(tmpconn));
100 tmpconn.aftype = AF_INET;
101 }
102
103 /*
104 * ref_link_by_name()
105 * ref_link_by_host()
106 *
107 * Finds and references a connect conf.
108 *
109 * inputs: link name
110 * output: pointer to ConnectConf
111 */
112 struct ConnectConf *
113 ref_link_by_name(const char *name)
114 {
115 dlink_node *ptr;
116 struct ConnectConf *conf;
117
118 DLINK_FOREACH(ptr, connect_confs.head)
119 {
120 conf = ptr->data;
121 if (match(conf->name, name))
122 return ref_link_by_ptr(conf);
123 }
124
125 return NULL;
126 }
127
128 struct ConnectConf *
129 ref_link_by_host(const char *name)
130 {
131 dlink_node *ptr;
132 struct ConnectConf *conf;
133
134 DLINK_FOREACH(ptr, connect_confs.head)
135 {
136 conf = ptr->data;
137 if (!irccmp(conf->host, name))
138 return ref_link_by_ptr(conf);
139 }
140
141 return NULL;
142 }
143
144 /*
145 * ref_link_by_ptr()
146 *
147 * Increments the reference counter of a connect conf.
148 *
149 * inputs: pointer to ConnectConf
150 * output: the same pointer
151 */
152 struct ConnectConf *
153 ref_link_by_ptr(struct ConnectConf *conf)
154 {
155 conf->refcnt++;
156 return conf;
157 }
158
159 /*
160 * unref_link()
161 *
162 * Decrements the reference counter of a connect conf.
163 * When it reaches zero, the conf gets freed.
164 *
165 * inputs: pointer to ConnectConf
166 * output: none
167 */
168 void
169 unref_link(struct ConnectConf *conf)
170 {
171 assert(conf->refcnt > 0);
172
173 if (!--conf->refcnt)
174 {
175 free_interior(conf);
176 MyFree(conf);
177 }
178 }
179
180 /*
181 * reset_connect()
182 *
183 * Sets up default values before a rehash.
184 *
185 * inputs: none
186 * output: none
187 */
188 static void *
189 reset_connect(va_list args)
190 {
191 while (connect_confs.head)
192 {
193 struct ConnectConf *conf = connect_confs.head->data;
194 dlinkDelete(&conf->node, &connect_confs);
195 unref_link(conf);
196 }
197
198 return pass_callback(hreset);
199 }
200
201 /*
202 * parse_aftype()
203 *
204 * Parses the "aftype=" field.
205 *
206 * inputs: pointer to a dlink list of strings
207 * output: none
208 */
209 static void
210 parse_aftype(void *plist, void *unused)
211 {
212 dlink_list *list = plist;
213
214 if (dlink_list_length(list) != 1)
215 {
216 err: parse_error("Syntax error");
217 return;
218 }
219
220 if (!irccmp(list->head->data, "ipv4"))
221 tmpconn.aftype = AF_INET;
222 #ifdef IPV6
223 else if (!irccmp(list->head->data, "ipv6"))
224 tmpconn.aftype = AF_INET6;
225 #endif
226 else
227 goto err;
228 }
229
230 /*
231 * parse_vhost()
232 *
233 * Parses the "vhost=" field.
234 *
235 * inputs: vhost IP string
236 * output: none
237 */
238 static void
239 parse_vhost(void *ipstr, void *unused)
240 {
241 struct addrinfo hints, *res;
242
243 memset(&hints, 0, sizeof(hints));
244
245 hints.ai_family = AF_UNSPEC;
246 hints.ai_socktype = SOCK_STREAM;
247 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
248
249 if (irc_getaddrinfo(ipstr, NULL, &hints, &res))
250 parse_error("Invalid netmask for server vhost(%s)", ipstr);
251 else
252 {
253 memcpy(&tmpconn.vhost, res->ai_addr, res->ai_addrlen);
254 tmpconn.vhost.ss.sin_family = res->ai_family;
255 tmpconn.vhost.ss_len = res->ai_addrlen;
256 irc_freeaddrinfo(res);
257 }
258 }
259
260 /*
261 * parse_password()
262 *
263 * Parses a password field.
264 *
265 * inputs:
266 * ppwd - password string
267 * pwhere - where to store it (or NULL for both send_ and accept_password)
268 * output: none
269 */
270 static void
271 parse_password(void *ppwd, void *pwhere)
272 {
273 char *pwd = ppwd;
274 char **where = pwhere;
275
276 if (pwd[0] == ':')
277 parse_error("Server passwords cannot begin with a colon");
278 else if (strchr(pwd, ' '))
279 parse_error("Server passwords cannot contain spaces");
280 else if (where)
281 {
282 MyFree(*where);
283 DupString(*where, pwd);
284 }
285 else
286 {
287 MyFree(tmpconn.send_password);
288 MyFree(tmpconn.accept_password);
289 DupString(tmpconn.send_password, pwd);
290 DupString(tmpconn.accept_password, pwd);
291 }
292 }
293
294 /*
295 * parse_class()
296 *
297 * Parses the "class=" field.
298 *
299 * inputs: pointer to class name
300 * output: none
301 */
302 static void
303 parse_class(void *name, void *unused)
304 {
305 if (tmpconn.class_ptr)
306 unref_class(tmpconn.class_ptr);
307
308 tmpconn.class_ptr = ref_class_by_name(name);
309 }
310
311 /*
312 * parse_mask()
313 *
314 * Parses a hub_mask/leaf_mask field.
315 *
316 * inputs:
317 * pmask - pointer to server name mask
318 * plist - where to add it
319 * output: none
320 */
321 static void
322 parse_mask(void *pmask, void *plist)
323 {
324 char *mask;
325 dlink_node *ptr = make_dlink_node();
326
327 DupString(mask, pmask);
328 dlinkAdd(mask, ptr, (dlink_list *) plist);
329 }
330
331 /*
332 * parse_rsa_pkfile()
333 *
334 * Parses the "rsa_public_key_file=" field.
335 *
336 * inputs: pointer to the file name
337 * output: none
338 */
339 static void
340 parse_rsa_pkfile(void *value, void *unused)
341 {
342 #ifndef HAVE_LIBCRYPTO
343 parse_error("no OpenSSL support");
344 #else
345 const char *str = value;
346 BIO *file = NULL;
347
348 if (tmpconn.rsa_public_key != NULL)
349 {
350 RSA_free(tmpconn.rsa_public_key);
351 tmpconn.rsa_public_key = NULL;
352 }
353
354 if ((file = BIO_new_file(str, "r")) == NULL)
355 {
356 parse_error("file doesn't exist");
357 return;
358 }
359
360 tmpconn.rsa_public_key = (RSA*) PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
361 if (tmpconn.rsa_public_key == NULL)
362 parse_error("key invalid; check key syntax");
363
364 BIO_set_close(file, BIO_CLOSE);
365 BIO_free(file);
366 #endif
367 }
368
369 /*
370 * parse_cipherpref()
371 *
372 * Parses the "cipher_preference=" field.
373 *
374 * inputs: pointer to a cipher name
375 * output: none
376 */
377 static void
378 parse_cipherpref(void *value, void *unused)
379 {
380 #ifndef HAVE_LIBCRYPTO
381 parse_error("no OpenSSL support");
382 #else
383 struct EncCapability *ecap;
384
385 tmpconn.cipher_preference = NULL;
386
387 for (ecap = CipherTable; ecap->name; ecap++)
388 if (!irccmp(ecap->name, value) && (ecap->cap & CAP_ENC_MASK))
389 {
390 tmpconn.cipher_preference = ecap;
391 break;
392 }
393
394 if (!tmpconn.cipher_preference)
395 parse_error("invalid cipher");
396 #endif
397 }
398
399 /*
400 * parse_flag()
401 *
402 * Parses an old-style switch.
403 *
404 * inputs:
405 * state - YES/NO casted to void
406 * flag - flag value casted to void
407 * output: none
408 */
409 static void
410 parse_flag(void *state, void *flag)
411 {
412 if (*(int *) state)
413 tmpconn.flags |= (unsigned long) flag;
414 else
415 tmpconn.flags &= ~((unsigned long) flag);
416 }
417
418 /*
419 * parse_flags()
420 *
421 * Handles "flags=" list.
422 *
423 * inputs: pointer to a dlink_list of flag names
424 * output: none
425 */
426 static void
427 parse_flags(void *list, void *unused)
428 {
429 const struct FlagMapping *p;
430 int errors = NO;
431 dlink_node *ptr;
432
433 DLINK_FOREACH(ptr, ((dlink_list *) list)->head)
434 {
435 const char *str = ptr->data;
436 int found = NO;
437
438 for (p = flag_mappings; p->name; ++p)
439 if (!irccmp(str, p->name))
440 {
441 found = YES;
442 tmpconn.flags |= p->flag;
443 break;
444 }
445
446 if (!found)
447 errors = YES;
448 }
449
450 if (errors)
451 parse_error("Invalid connect flags encountered, check your syntax");
452 }
453
454 /*
455 * after_connect()
456 *
457 * Called after parsing a single connect{} block.
458 *
459 * inputs: none
460 * output: none
461 */
462 static void
463 after_connect(void)
464 {
465 struct ConnectConf *conf;
466
467 if (!tmpconn.name || !tmpconn.class_ptr ||
468 (!tmpconn.send_password &&
469 #ifdef HAVE_LIBCRYPTO
470 !tmpconn.accept_password && !tmpconn.rsa_public_key))
471 #else
472 !tmpconn.accept_password))
473 #endif
474 {
475 parse_error("Incomplete connect{} block");
476 clear_temp();
477 return;
478 }
479
480 if (!tmpconn.host)
481 DupString(tmpconn.host, tmpconn.name);
482
483 conf = MyMalloc(sizeof(*conf));
484 memcpy(conf, &tmpconn, sizeof(*conf));
485 dlinkAdd(conf, &conf->node, &connect_confs);
486 ref_link_by_ptr(conf);
487
488 memset(&tmpconn, 0, sizeof(tmpconn));
489 }
490
491 /*
492 * report_connect()
493 *
494 * Sends a /stats C reply to the given client.
495 *
496 * inputs: client pointer
497 * output: none
498 */
499 void
500 report_connect(struct Client *source_p)
501 {
502 dlink_node *ptr;
503
504 DLINK_FOREACH(ptr, connect_confs.head)
505 {
506 char buf[12] = "*", *p = buf;
507 struct ConnectConf *conf = ptr->data;
508
509 if ((conf->flags & LINK_AUTOCONN))
510 *p++ = 'A';
511 if ((conf->flags & LINK_CRYPTLINK))
512 *p++ = 'C';
513 if (conf->fakename)
514 *p++ = 'M';
515 if ((conf->flags & LINK_TOPICBURST))
516 *p++ = 'T';
517 if ((conf->flags & LINK_COMPRESSED))
518 *p++ = 'Z';
519 if (p > buf)
520 *p = 0;
521
522 sendto_one(source_p, form_str(RPL_STATSCLINE),
523 ID_or_name(&me, source_p->from),
524 ID_or_name(source_p, source_p->from), 'C',
525 (!ServerHide.hide_server_ips && IsAdmin(source_p)) ?
526 conf->host : "255.255.255.255", buf, conf->name, conf->port,
527 conf->class_ptr->name);
528 }
529 }
530
531 /*
532 * report_hubleaf()
533 *
534 * Sends a /stats H reply to the given client.
535 *
536 * inputs: client pointer
537 * output: none
538 */
539 void
540 report_hubleaf(struct Client *to)
541 {
542 dlink_node *ptr, *ptr2;
543 struct ConnectConf *conf;
544
545 DLINK_FOREACH(ptr, connect_confs.head)
546 {
547 conf = ptr->data;
548 DLINK_FOREACH(ptr2, conf->hub_list.head)
549 sendto_one(to, form_str(RPL_STATSHLINE), ID_or_name(&me, to->from),
550 ID_or_name(to, to->from), 'H', ptr2->data, conf->name, 0, "*");
551 }
552
553 DLINK_FOREACH(ptr, connect_confs.head)
554 {
555 conf = ptr->data;
556 DLINK_FOREACH(ptr2, conf->leaf_list.head)
557 sendto_one(to, form_str(RPL_STATSLLINE), ID_or_name(&me, to->from),
558 ID_or_name(to, to->from), 'L', ptr2->data, conf->name, 0, "*");
559 }
560 }
561
562 /*
563 * init_connect()
564 *
565 * Defines the connect{} conf section.
566 *
567 * inputs: none
568 * output: none
569 */
570 void
571 init_connect(void)
572 {
573 struct ConfSection *s = add_conf_section("connect", 2);
574
575 hreset = install_hook(reset_conf, reset_connect);
576
577 s->before = clear_temp;
578
579 s->def_field = add_conf_field(s, "name", CT_STRING, NULL, &tmpconn.name);
580 add_conf_field(s, "host", CT_STRING, NULL, &tmpconn.host);
581 add_conf_field(s, "aftype", CT_LIST, parse_aftype, NULL);
582 add_conf_field(s, "port", CT_NUMBER, NULL, &tmpconn.port);
583 add_conf_field(s, "allow_host", CT_STRING, NULL, &tmpconn.allow_host);
584 add_conf_field(s, "vhost", CT_STRING, parse_vhost, NULL);
585 add_conf_field(s, "send_password", CT_STRING, parse_password,
586 &tmpconn.send_password);
587 add_conf_field(s, "accept_password", CT_STRING, parse_password,
588 &tmpconn.accept_password);
589 add_conf_field(s, "password", CT_STRING, parse_password, NULL);
590 add_conf_field(s, "fakename", CT_STRING, NULL, &tmpconn.fakename);
591 add_conf_field(s, "class", CT_STRING, parse_class, NULL);
592 add_conf_field(s, "hub_mask", CT_STRING, parse_mask, &tmpconn.hub_list);
593 add_conf_field(s, "leaf_mask", CT_STRING, parse_mask, &tmpconn.leaf_list);
594 add_conf_field(s, "rsa_public_key_file", CT_STRING, parse_rsa_pkfile, NULL);
595 add_conf_field(s, "cipher_preference", CT_STRING, parse_cipherpref, NULL);
596 add_conf_field(s, "flags", CT_LIST, parse_flags, NULL);
597 add_conf_field(s, "encrypted", CT_BOOL, parse_flag, (void *) LINK_CRYPTPWD);
598 add_conf_field(s, "cryptlink", CT_BOOL, parse_flag, (void *) LINK_CRYPTLINK);
599 add_conf_field(s, "compressed", CT_BOOL, parse_flag, (void *)
600 LINK_COMPRESSED);
601 add_conf_field(s, "autoconn", CT_BOOL, parse_flag, (void *) LINK_AUTOCONN);
602
603 s->after = after_connect;
604 }

Properties

Name Value
svn:eol-style native
svn:keywords "Id Revision"