📄 router.c
字号:
case event_OPEN: log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] authenticated as %s", comp->ip, comp->port, comp->s->auth_id); /* make a route for legacy components */ if(comp->legacy) { /* make sure the name is available */ if(xhash_get(comp->r->routes, s->req_to) != NULL) { sx_error(s, stream_err_HOST_UNKNOWN, "requested name is already in use"); /* !!! correct error? */ sx_close(s); return 0; } for(alias = comp->r->aliases; alias != NULL; alias = alias->next) if(strcmp(alias->name, s->req_to) == 0) { sx_error(s, stream_err_HOST_UNKNOWN, "requested name is already in use"); /* !!! correct error? */ sx_close(s); return 0; } xhash_put(comp->r->routes, pstrdup(xhash_pool(comp->r->routes), s->req_to), (void *) comp); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), s->req_to), (void *) comp); log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", s->req_to, comp->ip, comp->port); /* advertise the name */ _router_advertise(comp->r, s->req_to, comp, 0); /* this is a legacy component, so we don't tell it about other routes */ /* bind aliases */ for(alias = comp->r->aliases; alias != NULL; alias = alias->next) { if(strcmp(alias->target, s->req_to) == 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, s->req_to, comp->ip, comp->port); /* advertise name */ _router_advertise(comp->r, alias->name, comp, 0); } } } break; case event_PACKET: nad = (nad_t) data; /* preauth */ if(comp->s->state == state_STREAM) { /* non-legacy components can't do anything before auth */ if(!comp->legacy) { log_debug(ZONE, "stream is preauth, dropping packet"); nad_free(nad); return 0; } /* watch for handshake requests */ if(NAD_ENAME_L(nad, 0) != 9 || strncmp("handshake", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) != 0) { log_debug(ZONE, "unknown preauth packet %.*s, dropping", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } /* process incoming handshakes */ _router_process_handshake(comp, nad); return 0; } /* legacy processing */ if(comp->legacy) { log_debug(ZONE, "packet from legacy component, munging it"); sto.pc = sfrom.pc = comp->r->pc; attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_reset(&sto, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "invalid or missing 'to' address on legacy packet, dropping it"); nad_free(nad); return 0; } attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_reset(&sfrom, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "invalid or missing 'from' address on legacy packet, dropping it"); nad_free(nad); return 0; } /* rewrite component packets into client packets */ ns = nad_find_namespace(nad, 0, "jabber:component:accept", NULL); if(ns >= 0) { if(nad->elems[0].ns == ns) nad->elems[0].ns = nad->nss[nad->elems[0].ns].next; else { for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next); nad->nss[sns].next = nad->nss[nad->nss[sns].next].next; } } ns = nad_find_namespace(nad, 0, uri_CLIENT, NULL); if(ns < 0) { ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad->scope = -1; nad->nss[ns].next = nad->elems[0].ns; nad->elems[0].ns = ns; } nad->elems[0].my_ns = ns; /* wrap up the packet */ ns = nad_add_namespace(nad, uri_COMPONENT, "comp"); nad_wrap_elem(nad, 0, ns, "route"); nad_set_attr(nad, 0, -1, "to", to->domain, 0); nad_set_attr(nad, 0, -1, "from", from->domain, 0); } /* top element must be router scoped */ if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0) { log_debug(ZONE, "invalid packet namespace, dropping"); nad_free(nad); return 0; } /* bind a name to this component */ if(NAD_ENAME_L(nad, 0) == 4 && strncmp("bind", NAD_ENAME(nad, 0), 4) == 0) { _router_process_bind(comp, nad); return 0; } /* unbind a name from this component */ if(NAD_ENAME_L(nad, 0) == 6 && strncmp("unbind", NAD_ENAME(nad, 0), 6) == 0) { _router_process_unbind(comp, nad); return 0; } /* route packets */ if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) { _router_process_route(comp, nad); return 0; } /* throttle packets */ if(NAD_ENAME_L(nad, 0) == 8 && strncmp("throttle", NAD_ENAME(nad, 0), 8) == 0) { _router_process_throttle(comp, nad); return 0; } log_debug(ZONE, "unknown packet, dropping"); nad_free(nad); return 0; case event_CLOSED: mio_close(comp->r->mio, comp->fd); break; } return 0;}static int _router_accept_check(router_t r, int fd, char *ip) { rate_t rt; if(access_check(r->access, ip) == 0) { log_write(r->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd, ip); return 1; } if(r->conn_rate_total != 0) { rt = (rate_t) xhash_get(r->conn_rates, ip); if(rt == NULL) { rt = rate_new(r->conn_rate_total, r->conn_rate_seconds, r->conn_rate_wait); xhash_put(r->conn_rates, pstrdup(xhash_pool(r->conn_rates), ip), (void *) rt); } if(rate_check(rt) == 0) { log_write(r->log, LOG_NOTICE, "[%d] [%s] is being rate limited", fd, ip); return 1; } rate_add(rt, 1); } return 0;}static void _router_route_unbind_walker(xht routes, const char *key, void *val, void *arg) { component_t comp = (component_t) arg; xhash_zap(comp->r->routes, key); xhash_zap(comp->routes, key); if(comp->r->default_route != NULL && strcmp(key, comp->r->default_route) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", key); free(comp->r->default_route); comp->r->default_route = NULL; } log_write(comp->r->log, LOG_NOTICE, "[%s] offline", key); /* deadvertise name */ _router_advertise(comp->r, (char *) key, comp, 1);}int router_mio_callback(mio_t m, mio_action_t a, int fd, void *data, void *arg) { component_t comp = (component_t) arg; router_t r = (router_t) arg; struct sockaddr_storage sa; int namelen = sizeof(sa), port, nbytes; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd); ioctl(fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(comp->s); return 0; } return sx_can_read(comp->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd); return sx_can_write(comp->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd); r = comp->r; log_write(r->log, LOG_NOTICE, "[%s, port=%d] disconnect", comp->ip, comp->port); /* unbind names */ xhash_walk(comp->routes, _router_route_unbind_walker, (void *) comp); /* deregister component */ xhash_zap(r->components, comp->ipport); xhash_free(comp->routes); if(comp->tq != NULL) /* !!! bounce packets */ jqueue_free(comp->tq); rate_free(comp->rate); jqueue_push(comp->r->dead, (void *) comp->s, 0); free(comp); break; case action_ACCEPT: log_debug(ZONE, "accept action on fd %d", fd); getpeername(fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(r->log, LOG_NOTICE, "[%s, port=%d] connect", (char *) data, port); if(_router_accept_check(r, fd, (char *) data) != 0) return 1; comp = (component_t) malloc(sizeof(struct component_st)); memset(comp, 0, sizeof(struct component_st)); comp->r = r; comp->fd = fd; snprintf(comp->ip, INET6_ADDRSTRLEN, "%s", (char *) data); comp->port = port; snprintf(comp->ipport, INET6_ADDRSTRLEN, "%s:%d", comp->ip, comp->port); comp->s = sx_new(r->sx_env, fd, _router_sx_callback, (void *) comp); mio_app(m, fd, router_mio_callback, (void *) comp); if(r->byte_rate_total != 0) comp->rate = rate_new(r->byte_rate_total, r->byte_rate_seconds, r->byte_rate_wait); comp->routes = xhash_new(51); /* register component */ xhash_put(r->components, comp->ipport, (void *) comp);#ifdef HAVE_SSL sx_server_init(comp->s, SX_SSL_STARTTLS_OFFER | SX_SASL_OFFER | SX_SASL_MECH_PLAIN | SX_SASL_MECH_DIGESTMD5);#else sx_server_init(comp->s, SX_SASL_OFFER | SX_SASL_MECH_PLAIN | SX_SASL_MECH_DIGESTMD5);#endif break; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -