📄 listen.c
字号:
this = listen_alloc(RAD_LISTEN_PROXY); /* * Find an existing proxy socket to copy. * * FIXME: Make it per-realm, or per-home server! */ last_proxy_port = 0; old = NULL; last = &mainconfig.listen; for (tmp = mainconfig.listen; tmp != NULL; tmp = tmp->next) { if (tmp->type == RAD_LISTEN_PROXY) { sock = tmp->data; if (sock->port > last_proxy_port) { last_proxy_port = sock->port + 1; } if (!old) old = sock; } last = &(tmp->next); } if (!old) { listen_free(&this); return NULL; /* This is a serious error. */ } /* * FIXME: find a new IP address to listen on? * * This could likely be done in the "home server" * configuration, to have per-home-server source IP's. */ sock = this->data; memcpy(&sock->ipaddr, &old->ipaddr, sizeof(sock->ipaddr)); /* * Keep going until we find an unused port. */ for (port = last_proxy_port; port < 64000; port++) { sock->port = port; if (listen_bind(this) == 0) { /* * Add the new listener to the list of * listeners. */ *last = this; return this; } } listen_free(&this); return NULL;}static const FR_NAME_NUMBER listen_compare[] = { { "auth", RAD_LISTEN_AUTH }, { "acct", RAD_LISTEN_ACCT }, { "detail", RAD_LISTEN_DETAIL }, { "proxy", RAD_LISTEN_PROXY },#ifdef WITH_VMPS { "vmps", RAD_LISTEN_VQP },#endif#ifdef WITH_DHCP { "dhcp", RAD_LISTEN_DHCP },#else { "dhcp", RAD_LISTEN_NONE },#endif { NULL, 0 },};static rad_listen_t *listen_parse(CONF_SECTION *cs, const char *server){ int type, rcode; char *listen_type; rad_listen_t *this; listen_type = NULL; cf_log_info(cs, "listen {"); rcode = cf_item_parse(cs, "type", PW_TYPE_STRING_PTR, &listen_type, ""); if (rcode < 0) return NULL; if (rcode == 1) { free(listen_type); cf_log_err(cf_sectiontoitem(cs), "No type specified in listen section"); return NULL; } type = fr_str2int(listen_compare, listen_type, RAD_LISTEN_NONE); if (type == RAD_LISTEN_NONE) { cf_log_err(cf_sectiontoitem(cs), "Invalid type \"%s\" in listen section.", listen_type); free(listen_type); return NULL; } free(listen_type); /* * Allow listen sections in the default config to * refer to a server. */ if (!server) { rcode = cf_item_parse(cs, "virtual_server", PW_TYPE_STRING_PTR, &server, NULL); if (rcode == 1) { /* compatiblity with 2.0-pre */ rcode = cf_item_parse(cs, "server", PW_TYPE_STRING_PTR, &server, NULL); } if (rcode < 0) return NULL; } /* * Set up cross-type data. */ this = listen_alloc(type); this->server = server; this->fd = -1; /* * Call per-type parser. */ if (master_listen[type].parse(cs, this) < 0) { listen_free(&this); return NULL; } cf_log_info(cs, "}"); return this;}/* * Generate a list of listeners. Takes an input list of * listeners, too, so we don't close sockets with waiting packets. */int listen_init(CONF_SECTION *config, rad_listen_t **head){ int override = FALSE; int rcode; CONF_SECTION *cs; rad_listen_t **last; rad_listen_t *this; fr_ipaddr_t server_ipaddr; int auth_port = 0; int defined_proxy = 0; /* * We shouldn't be called with a pre-existing list. */ rad_assert(head && (*head == NULL)); last = head; server_ipaddr.af = AF_UNSPEC; /* * If the port is specified on the command-line, * it over-rides the configuration file. * * FIXME: If argv[0] == "vmpsd", then don't listen on auth/acct! */ if (mainconfig.port >= 0) auth_port = mainconfig.port; /* * If the IP address was configured on the command-line, * use that as the "bind_address" */ if (mainconfig.myip.af != AF_UNSPEC) { memcpy(&server_ipaddr, &mainconfig.myip, sizeof(server_ipaddr)); override = TRUE; goto bind_it; } /* * Else look for bind_address and/or listen sections. */ server_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE); rcode = cf_item_parse(config, "bind_address", PW_TYPE_IPADDR, &server_ipaddr.ipaddr.ip4addr, NULL); if (rcode < 0) return -1; /* error parsing it */ if (rcode == 0) { /* successfully parsed IPv4 */ listen_socket_t *sock; server_ipaddr.af = AF_INET; radlog(L_INFO, "WARNING: The directive 'bind_adress' is deprecated, and will be removed in future versions of FreeRADIUS. Please edit the configuration files to use the directive 'listen'."); bind_it:#ifdef WITH_VMPS if (strcmp(progname, "vmpsd") == 0) { this = listen_alloc(RAD_LISTEN_VQP); if (!auth_port) auth_port = 1589; } else#endif this = listen_alloc(RAD_LISTEN_AUTH); sock = this->data; sock->ipaddr = server_ipaddr; sock->port = auth_port; sock->clients = clients_parse_section(config); if (!sock->clients) { cf_log_err(cf_sectiontoitem(config), "Failed to find any clients for this listen section"); return -1; } if (listen_bind(this) < 0) { listen_free(&this); listen_free(head); radlog(L_ERR, "There appears to be another RADIUS server running on the authentication port %d", sock->port); return -1; } auth_port = sock->port; /* may have been updated in listen_bind */ if (override) { cs = cf_section_sub_find_name2(config, "server", mainconfig.name); if (cs) this->server = mainconfig.name; } *last = this; last = &(this->next);#ifdef WITH_VMPS /* * No acct for vmpsd */ if (strcmp(progname, "vmpsd") == 0) goto do_proxy;#endif /* * Open Accounting Socket. * * If we haven't already gotten acct_port from * /etc/services, then make it auth_port + 1. */ this = listen_alloc(RAD_LISTEN_ACCT); sock = this->data; /* * Create the accounting socket. * * The accounting port is always the * authentication port + 1 */ sock->ipaddr = server_ipaddr; sock->port = auth_port + 1; sock->clients = clients_parse_section(config); if (!sock->clients) { cf_log_err(cf_sectiontoitem(config), "Failed to find any clients for this listen section"); return -1; } if (listen_bind(this) < 0) { listen_free(&this); listen_free(head); radlog(L_ERR, "There appears to be another RADIUS server running on the accounting port %d", sock->port); return -1; } if (override) { cs = cf_section_sub_find_name2(config, "server", mainconfig.name); if (cs) this->server = mainconfig.name; } *last = this; last = &(this->next); } else if (mainconfig.port > 0) { /* no bind address, but a port */ radlog(L_ERR, "The command-line says \"-p %d\", but there is no associated IP address to use", mainconfig.port); return -1; } /* * They specified an IP on the command-line, ignore * all listen sections except the one in '-n'. */ if (mainconfig.myip.af != AF_UNSPEC) { CONF_SECTION *subcs; const char *name2 = cf_section_name2(cs); cs = cf_section_sub_find_name2(config, "server", mainconfig.name); if (!cs) goto do_proxy; /* * Should really abstract this code... */ for (subcs = cf_subsection_find_next(cs, NULL, "listen"); subcs != NULL; subcs = cf_subsection_find_next(cs, subcs, "listen")) { this = listen_parse(subcs, name2); if (!this) { listen_free(head); return -1; } if (this->type == RAD_LISTEN_PROXY) defined_proxy = 1; *last = this; last = &(this->next); } /* loop over "listen" directives in server <foo> */ goto do_proxy; } /* * Walk through the "listen" sections, if they exist. */ for (cs = cf_subsection_find_next(config, NULL, "listen"); cs != NULL; cs = cf_subsection_find_next(config, cs, "listen")) { this = listen_parse(cs, NULL); if (!this) { listen_free(head); return -1; } if (this->type == RAD_LISTEN_PROXY) defined_proxy = 1; *last = this; last = &(this->next); } /* * Check virtual servers for "listen" sections, too. * * FIXME: Move to virtual server init? */ for (cs = cf_subsection_find_next(config, NULL, "server"); cs != NULL; cs = cf_subsection_find_next(config, cs, "server")) { CONF_SECTION *subcs; const char *name2 = cf_section_name2(cs); for (subcs = cf_subsection_find_next(cs, NULL, "listen"); subcs != NULL; subcs = cf_subsection_find_next(cs, subcs, "listen")) { this = listen_parse(subcs, name2); if (!this) { listen_free(head); return -1; } if (this->type == RAD_LISTEN_PROXY) { radlog(L_ERR, "Error: listen type \"proxy\" Cannot appear in a virtual server section"); listen_free(head); return -1; } *last = this; last = &(this->next); } /* loop over "listen" directives in virtual servers */ } /* loop over virtual servers */ /* * If we're proxying requests, open the proxy FD. * Otherwise, don't do anything. */ do_proxy: if (mainconfig.proxy_requests == TRUE) { int port = -1; listen_socket_t *sock = NULL; /* * No sockets to receive packets, therefore * proxying is pointless. */ if (!*head) return -1; if (defined_proxy) goto do_snmp; /* * Find the first authentication port, * and use it */ for (this = *head; this != NULL; this = this->next) { if (this->type == RAD_LISTEN_AUTH) { sock = this->data; if (server_ipaddr.af == AF_UNSPEC) { server_ipaddr = sock->ipaddr; } port = sock->port + 2; /* skip acct port */ break; } if (this->type == RAD_LISTEN_VQP) { sock = this->data; if (server_ipaddr.af == AF_UNSPEC) { server_ipaddr = sock->ipaddr; } port = sock->port + 1; break; } } if (port < 0) port = 1024 + (fr_rand() & 0x1ff); /* * Address is still unspecified, use IPv4. */ if (server_ipaddr.af == AF_UNSPEC) { server_ipaddr.af = AF_INET; server_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_ANY); } this = listen_alloc(RAD_LISTEN_PROXY); sock = this->data; /* * Create the first proxy socket. */ sock->ipaddr = server_ipaddr; /* * Try to find a proxy port (value doesn't matter) */ for (sock->port = port; sock->port < 64000; sock->port++) { if (listen_bind(this) == 0) { *last = this; last = &(this->next); /* just in case */ break; } } if (sock->port >= 64000) { listen_free(head); listen_free(&this); radlog(L_ERR, "Failed to open socket for proxying"); return -1; } } do_snmp:#ifdef WITH_SNMP if (radius_snmp_init(config)) { this = rad_malloc(sizeof(*this)); memset(this, 0, sizeof(*this)); this->type = RAD_LISTEN_SNMP; this->fd = rad_snmp.smux_fd; this->recv = radius_snmp_recv; this->print = radius_snmp_print; *last = this; last = &(this->next); }#endif return 0;}/* * Free a linked list of listeners; */void listen_free(rad_listen_t **head){ rad_listen_t *this; if (!head || !*head) return; this = *head; while (this) { rad_listen_t *next = this->next; /* * Other code may have eaten the FD. */ if (this->fd >= 0) close(this->fd); if (master_listen[this->type].free) { master_listen[this->type].free(this); } free(this->data); free(this); this = next; } *head = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -