📄 router.c
字号:
/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA */#include "router.h"/** info for broadcasts */typedef struct broadcast_st { router_t r; component_t src; nad_t nad;} *broadcast_t;/** broadcast a packet */static void _router_broadcast(xht routes, const char *key, void *val, void *arg) { broadcast_t bc = (broadcast_t) arg; component_t comp = (component_t) val; /* I don't care about myself or the elderly (!?) */ if(comp == bc->src || comp->legacy) return; sx_nad_write(comp->s, nad_copy(bc->nad));}/** domain advertisement */static void _router_advertise(router_t r, char *domain, component_t src, int unavail) { struct broadcast_st bc; int ns; log_debug(ZONE, "advertising %s to all routes (unavail=%d)", domain, unavail); bc.r = r; bc.src = src; /* create a new packet */ bc.nad = nad_new(src->s->nad_cache); ns = nad_add_namespace(bc.nad, uri_COMPONENT, NULL); nad_append_elem(bc.nad, ns, "presence", 0); nad_append_attr(bc.nad, -1, "from", domain); if(unavail) nad_append_attr(bc.nad, -1, "type", "unavailable"); xhash_walk(r->routes, _router_broadcast, (void *) &bc); nad_free(bc.nad);}/** tell a component about all the others */static void _router_advertise_reverse(xht routes, const char *key, void *val, void *arg) { component_t dest = (component_t) arg, comp = (component_t) val; int ns; nad_t nad; /* don't tell me about myself */ if(comp == dest) return; log_debug(ZONE, "informing component about %s", key); /* create a new packet */ nad = nad_new(dest->s->nad_cache); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "presence", 0); nad_append_attr(nad, -1, "from", (char *) key); sx_nad_write(dest->s, nad);}static void _router_process_handshake(component_t comp, nad_t nad) { char *hash; int hashlen; /* must have a hash as cdata */ if(NAD_CDATA_L(nad, 0) != 40) { log_debug(ZONE, "handshake isn't long enough to be a sha1 hash"); sx_error(comp->s, stream_err_NOT_AUTHORIZED, "handshake isn't long enough to be a sha1 hash"); sx_close(comp->s); nad_free(nad); return; } /* make room for shahash_r to work .. needs at least 41 chars */ hashlen = strlen(comp->s->id) + strlen(comp->r->local_secret) + 1; if(hashlen < 41) hashlen = 41; /* build the creds and hash them */ hash = (char *) malloc(sizeof(char) * hashlen); sprintf(hash, "%s%s", comp->s->id, comp->r->local_secret); shahash_r(hash, hash); /* check */ log_debug(ZONE, "checking their hash %.*s against our hash %s", 40, NAD_CDATA(nad, 0), hash); if(strncmp(hash, NAD_CDATA(nad, 0), 40) == 0) { log_debug(ZONE, "handshake succeeded"); free(hash); /* respond */ nad->elems[0].icdata = nad->elems[0].itail = -1; nad->elems[0].lcdata = nad->elems[0].ltail = 0; sx_nad_write(comp->s, nad); sx_auth(comp->s, "handshake", comp->s->req_to); return; } log_debug(ZONE, "auth failed"); free(hash); /* failed, let them know */ sx_error(comp->s, stream_err_NOT_AUTHORIZED, "hash didn't match, auth failed"); sx_close(comp->s); nad_free(nad);}static void _router_process_bind(component_t comp, nad_t nad) { int attr; jid_t name; alias_t alias; char *user, *c; attr = nad_find_attr(nad, 0, -1, "name", NULL); if(attr < 0 || (name = jid_new(comp->r->pc, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "no or invalid 'name' on bind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } user = strdup(comp->s->auth_id); c = strchr(user, '@'); if(c != NULL) *c = '\0'; if(strcmp(user, name->domain) != 0 && !aci_check(comp->r->aci, "bind", user)) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but their username (%s) is not permitted to bind other names", comp->ip, comp->port, name->domain, user); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } if(xhash_get(comp->r->routes, name->domain) != NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but it's already bound", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } for(alias = comp->r->aliases; alias != NULL; alias = alias->next) if(strcmp(alias->name, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but that name is aliased", comp->ip, comp->port); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } /* default route */ if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "default", 1) >= 0) { if(!aci_check(comp->r->aci, "default-route", user)) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but their username (%s) is not permitted to set a default route", comp->ip, comp->port, name->domain, user); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } if(comp->r->default_route != NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but one already exists", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } log_write(comp->r->log, LOG_NOTICE, "[%s] set as default route", name->domain); comp->r->default_route = strdup(name->domain); } /* log sinks */ if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "log", 1) >= 0) { if(!aci_check(comp->r->aci, "log", user)) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as a log sink, but their username (%s) is not permitted to do this", comp->ip, comp->port, name->domain, user); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } log_write(comp->r->log, LOG_NOTICE, "[%s] set as log sink", name->domain); xhash_put(comp->r->log_sinks, pstrdup(xhash_pool(comp->r->log_sinks), name->domain), (void *) comp); } free(user); xhash_put(comp->r->routes, pstrdup(xhash_pool(comp->r->routes), name->domain), (void *) comp); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), name->domain), (void *) comp); log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", name->domain, comp->ip, comp->port); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* advertise name */ _router_advertise(comp->r, name->domain, comp, 0); /* tell the new component about everyone else */ xhash_walk(comp->r->routes, _router_advertise_reverse, (void *) comp); /* bind aliases */ for(alias = comp->r->aliases; alias != NULL; alias = alias->next) { if(strcmp(alias->target, name->domain) == 0) { xhash_put(comp->r->routes, pstrdup(xhash_pool(comp->r->routes), alias->name), (void *) comp); xhash_put(comp->routes, pstrdup(xhash_pool(comp->r->routes), alias->name), (void *) comp); log_write(comp->r->log, LOG_NOTICE, "[%s] online (alias of '%s', bound to %s, port %d)", alias->name, name->domain, comp->ip, comp->port); /* advertise name */ _router_advertise(comp->r, alias->name, comp, 0); } } /* done with this */ jid_free(name);}static void _router_process_unbind(component_t comp, nad_t nad) { int attr; jid_t name; attr = nad_find_attr(nad, 0, -1, "name", NULL); if(attr < 0 || (name = jid_new(comp->r->pc, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "no or invalid 'name' on unbind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } if(xhash_get(comp->routes, name->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to unbind '%s', but it's not bound to this component", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "404", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } xhash_zap(comp->r->routes, name->domain); xhash_zap(comp->routes, name->domain); if(comp->r->default_route != NULL && strcmp(comp->r->default_route, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", name->domain); free(comp->r->default_route); comp->r->default_route = NULL; } log_write(comp->r->log, LOG_NOTICE, "[%s] offline", name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* deadvertise name */ _router_advertise(comp->r, name->domain, comp, 1); jid_free(name);}static void _router_comp_write(component_t comp, nad_t nad) { int attr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -