X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Flisten.c;h=b6e2b4dbcd237b62f8b0630455123853aa0b9ab4;hb=1147ab4f2843e6deee5fd07f2b716de7cbb1675b;hp=31af1ad3da514a3cff6cfc92dea8e0688ae26bb9;hpb=bc889736922bdf8ecdc906ea174204ae528a38f0;p=freeradius.git diff --git a/src/main/listen.c b/src/main/listen.c index 31af1ad..b6e2b4d 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -201,7 +201,8 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener, * can be defined. */ rad_assert(client->dynamic == 0); - } else { + + } else if (!client->dynamic && client->rate_limit) { /* * The IP is unknown, so we've found an enclosing * network. Enable DoS protection. We only @@ -293,7 +294,7 @@ static int rad_status_server(REQUEST *request) case RAD_LISTEN_NONE: #endif case RAD_LISTEN_AUTH: - dval = dict_valbyname(PW_AUTZ_TYPE, "Status-Server"); + dval = dict_valbyname(PW_AUTZ_TYPE, 0, "Status-Server"); if (dval) { rcode = module_authorize(dval->value, request); } else { @@ -320,7 +321,7 @@ static int rad_status_server(REQUEST *request) #ifdef WITH_ACCOUNTING case RAD_LISTEN_ACCT: - dval = dict_valbyname(PW_ACCT_TYPE, "Status-Server"); + dval = dict_valbyname(PW_ACCT_TYPE, 0, "Status-Server"); if (dval) { rcode = module_accounting(dval->value, request); } else { @@ -347,7 +348,7 @@ static int rad_status_server(REQUEST *request) * the WG. We like it, so it goes in here. */ case RAD_LISTEN_COA: - dval = dict_valbyname(PW_RECV_COA_TYPE, "Status-Server"); + dval = dict_valbyname(PW_RECV_COA_TYPE, 0, "Status-Server"); if (dval) { rcode = module_recv_coa(dval->value, request); } else { @@ -404,13 +405,14 @@ static int auth_tcp_recv(rad_listen_t *listener, sock->packet->sockfd = listener->fd; sock->packet->src_ipaddr = sock->other_ipaddr; sock->packet->src_port = sock->other_port; + sock->packet->dst_ipaddr = sock->my_ipaddr; + sock->packet->dst_port = sock->my_port; } /* * Grab the packet currently being processed. */ packet = sock->packet; - sock->packet = NULL; rcode = fr_tcp_read_packet(packet, 0); @@ -419,7 +421,6 @@ static int auth_tcp_recv(rad_listen_t *listener, * so that we'll read more data when it's ready. */ if (rcode == 0) { - sock->packet = packet; return 0; } @@ -432,8 +433,6 @@ static int auth_tcp_recv(rad_listen_t *listener, } if (rcode < 0) { /* error or connection reset */ - rad_free(&packet); - listener->status = RAD_LISTEN_STATUS_REMOVE_FD; /* @@ -459,7 +458,6 @@ static int auth_tcp_recv(rad_listen_t *listener, * * It is instead free'd in remove_from_request_hash() */ - return 0; } @@ -476,37 +474,34 @@ static int auth_tcp_recv(rad_listen_t *listener, case PW_STATUS_SERVER: if (!mainconfig.status_server) { - rad_free(&packet); RAD_STATS_TYPE_INC(listener, total_packets_dropped); RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped); DEBUG("WARNING: Ignoring Status-Server request due to security configuration"); + rad_free(&sock->packet); return 0; } fun = rad_status_server; break; default: - rad_free(&packet); RAD_STATS_INC(radius_auth_stats.total_unknown_types); RAD_STATS_CLIENT_INC(listener, client, total_unknown_types); DEBUG("Invalid packet code %d sent to authentication port from client %s port %d : IGNORED", packet->code, client->shortname, packet->src_port); + rad_free(&sock->packet); return 0; - break; } /* switch over packet types */ if (!received_request(listener, packet, prequest, sock->client)) { RAD_STATS_TYPE_INC(listener, total_packets_dropped); RAD_STATS_CLIENT_INC(listener, sock->client, total_packets_dropped); - rad_free(&packet); + rad_free(&sock->packet); return 0; } - packet->dst_ipaddr = sock->my_ipaddr; - packet->dst_port = sock->my_port; - *pfun = fun; + sock->packet = NULL; /* we have no need for more partial reads */ return 1; } @@ -625,7 +620,7 @@ static int auth_tcp_accept(rad_listen_t *listener, /* * This function is stupid and complicated. */ -static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize) +static int socket_print(const rad_listen_t *this, char *buffer, size_t bufsize) { size_t len; listen_socket_t *sock = this->data; @@ -682,12 +677,10 @@ static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize) ADDSTRING(name); -#ifdef SO_BINDTODEVICE if (sock->interface) { ADDSTRING(" interface "); ADDSTRING(sock->interface); } -#endif #ifdef WITH_TCP if (this->recv == auth_tcp_accept) { @@ -732,6 +725,7 @@ static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize) return 1; } +#ifdef WITH_PROXY /* * Maybe it's a socket that we opened to a home server. */ @@ -762,7 +756,8 @@ static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize) return 1; } -#endif +#endif /* WITH_PROXY */ +#endif /* WITH_TCP */ ADDSTRING(" address "); @@ -789,6 +784,8 @@ static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize) return 1; } +extern int check_config; /* radiusd.c */ + /* * Parse an authentication or accounting socket. @@ -873,28 +870,38 @@ static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this) * TCP requires a destination IP for sockets. * UDP doesn't, so it's allowed. */ +#ifdef WITH_PROXY if ((this->type == RAD_LISTEN_PROXY) && (sock->proto != IPPROTO_UDP)) { cf_log_err(cf_sectiontoitem(cs), "Proxy listeners can only listen on proto = udp"); return -1; } -#endif +#endif /* WITH_PROXY */ +#endif /* WITH_TCP */ } sock->my_ipaddr = ipaddr; sock->my_port = listen_port; + if (check_config) { + if (home_server_find(&sock->my_ipaddr, sock->my_port, sock->proto)) { + char buffer[128]; + + DEBUG("ERROR: We have been asked to listen on %s port %d, which is also listed as a home server. This can create a proxy loop.", + ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)), + sock->my_port); + return -1; + } + + return 0; /* don't do anything */ + } + /* * If we can bind to interfaces, do so, * else don't. */ if (cf_pair_find(cs, "interface")) { -#ifndef SO_BINDTODEVICE - cf_log_err(cf_sectiontoitem(cs), - "System does not support binding to interfaces. Delete this line from the configuration file."); - return -1; -#else const char *value; CONF_PAIR *cp = cf_pair_find(cs, "interface"); @@ -906,7 +913,6 @@ static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this) return -1; } sock->interface = value; -#endif } #ifdef WITH_DHCP @@ -1343,9 +1349,9 @@ static int rad_coa_reply(REQUEST *request) /* * Inform the user about RFC requirements. */ - s1 = pairfind(request->proxy->vps, PW_STATE); + s1 = pairfind(request->proxy->vps, PW_STATE, 0); if (s1) { - s2 = pairfind(request->proxy_reply->vps, PW_STATE); + s2 = pairfind(request->proxy_reply->vps, PW_STATE, 0); if (!s2) { DEBUG("WARNING: Client was sent State in CoA, and did not respond with State."); @@ -1399,10 +1405,10 @@ static int rad_coa_recv(REQUEST *request) * with Service-Type = Authorize-Only, it MUST * have a State attribute in it. */ - vp = pairfind(request->packet->vps, PW_SERVICE_TYPE); + vp = pairfind(request->packet->vps, PW_SERVICE_TYPE, 0); if (request->packet->code == PW_COA_REQUEST) { if (vp && (vp->vp_integer == 17)) { - vp = pairfind(request->packet->vps, PW_STATE); + vp = pairfind(request->packet->vps, PW_STATE, 0); if (!vp || (vp->length == 0)) { RDEBUG("ERROR: CoA-Request with Service-Type = Authorize-Only MUST contain a State attribute"); request->reply->code = PW_COA_NAK; @@ -1450,7 +1456,7 @@ static int rad_coa_recv(REQUEST *request) * Copy State from the request to the reply. * See RFC 5176 Section 3.3. */ - vp = paircopy2(request->packet->vps, PW_STATE); + vp = paircopy2(request->packet->vps, PW_STATE, 0); if (vp) pairadd(&request->reply->vps, vp); /* @@ -1830,7 +1836,7 @@ static const rad_listen_master_t master_listen[RAD_LISTEN_MAX] = { #ifdef WITH_COMMAND_SOCKET /* TCP command socket */ - { command_socket_parse, NULL, + { command_socket_parse, command_socket_free, command_domain_accept, command_domain_send, command_socket_print, command_socket_encode, command_socket_decode }, #endif @@ -1917,12 +1923,17 @@ static int listen_bind(rad_listen_t *this) #ifdef WITH_COA case RAD_LISTEN_COA: - sock->my_port = PW_COA_UDP_PORT; + svp = getservbyname ("radius-dynauth", "udp"); + if (svp != NULL) { + sock->my_port = ntohs(svp->s_port); + } else { + sock->my_port = PW_COA_UDP_PORT; + } break; #endif default: - radlog(L_ERR, "ERROR: Non-fatal internal sanity check failed in bind."); + DEBUG("WARNING: Internal sanity check failed in binding to socket. Ignoring problem."); return -1; } } @@ -1936,11 +1947,11 @@ static int listen_bind(rad_listen_t *this) return -1; } -#ifdef SO_BINDTODEVICE /* * Bind to a device BEFORE touching IP addresses. */ if (sock->interface) { +#ifdef SO_BINDTODEVICE struct ifreq ifreq; strcpy(ifreq.ifr_name, sock->interface); @@ -1954,8 +1965,43 @@ static int listen_bind(rad_listen_t *this) sock->interface, strerror(errno)); return -1; } /* else it worked. */ - } +#else +#ifdef HAVE_STRUCT_SOCKADDR_IN6 +#ifdef HAVE_NET_IF_H + /* + * Odds are that any system supporting "bind to + * device" also supports IPv6, so this next bit + * isn't necessary. But it's here for + * completeness. + * + * If we're doing IPv6, and the scope hasn't yet + * been defined, set the scope to the scope of + * the interface. + */ + if (sock->my_ipaddr.af == AF_INET6) { + if (sock->my_ipaddr.scope == 0) { + sock->my_ipaddr.scope = if_nametoindex(sock->interface); + if (sock->my_ipaddr.scope == 0) { + close(this->fd); + radlog(L_ERR, "Failed finding interface %s: %s", + sock->interface, strerror(errno)); + return -1; + } + } /* else scope was defined: we're OK. */ + } else +#endif +#endif + /* + * IPv4: no link local addresses, + * and no bind to device. + */ + { + close(this->fd); + radlog(L_ERR, "Failed binding to interface %s: \"bind to device\" is unsupported", sock->interface); + return -1; + } #endif + } #ifdef WITH_TCP if (sock->proto == IPPROTO_TCP) { @@ -2283,7 +2329,10 @@ int proxy_new_listener(home_server *home, int src_port) /* * Tell the event loop that we have a new FD */ - event_new_fd(this); + if (!event_new_fd(this)) { + listen_free(&this); + return 0; + } return 1; } @@ -2396,6 +2445,28 @@ static rad_listen_t *listen_parse(CONF_SECTION *cs, const char *server) return this; } +#ifdef WITH_PROXY +static int is_loopback(const fr_ipaddr_t *ipaddr) +{ + /* + * We shouldn't proxy on loopback. + */ + if ((ipaddr->af == AF_INET) && + (ipaddr->ipaddr.ip4addr.s_addr == htonl(INADDR_LOOPBACK))) { + return 1; + } + +#ifdef HAVE_STRUCT_SOCKADDR_IN6 + if ((ipaddr->af == AF_INET6) && + (IN6_IS_ADDR_LINKLOCAL(&ipaddr->ipaddr.ip6addr))) { + return 1; + } +#endif + + return 0; +} +#endif + /* * Generate a list of listeners. Takes an input list of * listeners, too, so we don't close sockets with waiting packets. @@ -2453,7 +2524,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) 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'."); + radlog(L_INFO, "WARNING: The directive 'bind_address' 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 @@ -2622,6 +2693,15 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) add_sockets: /* + * No sockets to receive packets, this is an error. + * proxying is pointless. + */ + if (!*head) { + radlog(L_ERR, "The server is not configured to listen on any ports. Cannot start."); + return -1; + } + + /* * Print out which sockets we're listening on, and * add them to the event list. */ @@ -2651,10 +2731,7 @@ add_sockets: /* * */ -#ifdef WITH_TCP home.proto = IPPROTO_UDP; -#endif - home.src_ipaddr = server_ipaddr; /* @@ -2664,6 +2741,9 @@ add_sockets: for (this = *head; this != NULL; this = this->next) { if (this->type == RAD_LISTEN_AUTH) { sock = this->data; + + if (is_loopback(&sock->my_ipaddr)) continue; + if (home.src_ipaddr.af == AF_UNSPEC) { home.src_ipaddr = sock->my_ipaddr; } @@ -2673,6 +2753,9 @@ add_sockets: #ifdef WITH_ACCT if (this->type == RAD_LISTEN_ACCT) { sock = this->data; + + if (is_loopback(&sock->my_ipaddr)) continue; + if (home.src_ipaddr.af == AF_UNSPEC) { home.src_ipaddr = sock->my_ipaddr; } @@ -2732,12 +2815,12 @@ void listen_free(rad_listen_t **head) } #ifdef WITH_TCP - if ((this->type == RAD_LISTEN_AUTH) || + if ((this->type == RAD_LISTEN_AUTH) #ifdef WITH_ACCT - (this->type == RAD_LISTEN_ACCT) || + || (this->type == RAD_LISTEN_ACCT) #endif #ifdef WITH_PROXY - (this->type == RAD_LISTEN_PROXY) + || (this->type == RAD_LISTEN_PROXY) #endif ) { listen_socket_t *sock = this->data; @@ -2763,8 +2846,11 @@ RADCLIENT_LIST *listener_find_client_list(const fr_ipaddr_t *ipaddr, for (this = mainconfig.listen; this != NULL; this = this->next) { listen_socket_t *sock; - if ((this->type != RAD_LISTEN_AUTH) && - (this->type != RAD_LISTEN_ACCT)) continue; + if ((this->type != RAD_LISTEN_AUTH) +#ifdef WITH_ACCOUNTING + && (this->type != RAD_LISTEN_ACCT) +#endif + ) continue; sock = this->data; @@ -2789,8 +2875,11 @@ rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port) * FIXME: For TCP, ignore the *secondary* * listeners associated with the main socket. */ - if ((this->type != RAD_LISTEN_AUTH) && - (this->type != RAD_LISTEN_ACCT)) continue; + if ((this->type != RAD_LISTEN_AUTH) +#ifdef WITH_ACCOUNTING + && (this->type != RAD_LISTEN_ACCT) +#endif + ) continue; sock = this->data; @@ -2800,18 +2889,9 @@ rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port) } if ((sock->my_port == port) && - ((sock->my_ipaddr.af == AF_INET) && - (sock->my_ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY))) { + fr_inaddr_any(&sock->my_ipaddr)) { return this; } - -#ifdef HAVE_STRUCT_SOCKADDR_IN6 - if ((sock->my_port == port) && - (sock->my_ipaddr.af == AF_INET6) && - (IN6_IS_ADDR_UNSPECIFIED(&sock->my_ipaddr.ipaddr.ip6addr))) { - return this; - } -#endif } return NULL;