X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Flisten.c;h=e82d5850fe07121ce557ec420255e7825b9b7460;hb=e9831edfd3d9f38e6996d6e0e655feb0e1547be8;hp=b52f43c680b418e7eec991df972cf24114f8ec24;hpb=f1120bb8189caeba928f15caa77a22a494f8a550;p=freeradius.git diff --git a/src/main/listen.c b/src/main/listen.c index b52f43c..e82d585 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -50,6 +50,19 @@ RCSID("$Id$") #endif +void print_packet(RADIUS_PACKET *packet) +{ + char src[256], dst[256]; + + ip_ntoh(&packet->src_ipaddr, src, sizeof(src)); + ip_ntoh(&packet->dst_ipaddr, dst, sizeof(dst)); + + fprintf(stderr, "ID %d: %s %d -> %s %d\n", packet->id, + src, packet->src_port, dst, packet->dst_port); + +} + + /* * We'll use this below. */ @@ -66,18 +79,6 @@ typedef struct rad_listen_master_t { rad_listen_decode_t decode; } rad_listen_master_t; -typedef struct listen_socket_t { - /* - * For normal sockets. - */ - fr_ipaddr_t ipaddr; - int port; -#ifdef SO_BINDTODEVICE - const char *interface; -#endif - RADCLIENT_LIST *clients; -} listen_socket_t; - static rad_listen_t *listen_alloc(RAD_LISTEN_TYPE type); /* @@ -94,24 +95,21 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener, time_t now; RADCLIENT *client; RADCLIENT_LIST *clients; + listen_socket_t *sock; rad_assert(listener != NULL); rad_assert(ipaddr != NULL); - clients = ((listen_socket_t *)listener->data)->clients; + sock = listener->data; + clients = sock->clients; /* * This HAS to have been initialized previously. */ rad_assert(clients != NULL); - client = client_find(clients, ipaddr -#ifdef WITH_TCP - , IPPROTO_UDP -#endif - ); + client = client_find(clients, ipaddr,sock->proto); if (!client) { - static time_t last_printed = 0; char name[256], buffer[128]; #ifdef WITH_DYNAMIC_CLIENTS @@ -119,11 +117,13 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener, #endif /* - * DoS attack quenching, but only in debug mode. + * DoS attack quenching, but only in daemon mode. * If they're running in debug mode, show them * every packet. */ if (debug_flag == 0) { + static time_t last_printed = 0; + now = time(NULL); if (last_printed == now) return NULL; @@ -132,10 +132,16 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener, listener->print(listener, name, sizeof(name)); - radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d", - name, inet_ntop(ipaddr->af, &ipaddr->ipaddr, - buffer, sizeof(buffer)), - src_port); + radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d" +#ifdef WITH_TCP + " proto %s" +#endif + , name, inet_ntop(ipaddr->af, &ipaddr->ipaddr, + buffer, sizeof(buffer)), src_port +#ifdef WITH_TCP + , (sock->proto == IPPROTO_UDP) ? "udp" : "tcp" +#endif + ); return NULL; } @@ -181,11 +187,7 @@ RADCLIENT *client_listener_find(const rad_listen_t *listener, /* * Go find the enclosing network again. */ - client = client_find(clients, ipaddr -#ifdef WITH_TCP - , IPPROTO_UDP -#endif - ); + client = client_find(clients, ipaddr, sock->proto); /* * WTF? @@ -199,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 @@ -291,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 { @@ -318,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 { @@ -345,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 { @@ -382,7 +385,241 @@ static int rad_status_server(REQUEST *request) return 0; } +#ifdef WITH_TCP +static int auth_tcp_recv(rad_listen_t *listener, + RAD_REQUEST_FUNP *pfun, REQUEST **prequest) +{ + int rcode; + RADIUS_PACKET *packet; + RAD_REQUEST_FUNP fun = NULL; + listen_socket_t *sock = listener->data; + RADCLIENT *client = sock->client; + + /* + * Allocate a packet for partial reads. + */ + if (!sock->packet) { + sock->packet = rad_alloc(0); + if (!sock->packet) return 0; + + 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; + + rcode = fr_tcp_read_packet(packet, 0); + + /* + * Still only a partial packet. Put it back, and return, + * so that we'll read more data when it's ready. + */ + if (rcode == 0) { + return 0; + } + + if (rcode == -1) { /* error reading packet */ + char buffer[256]; + + radlog(L_ERR, "Invalid packet from %s port %d: closing socket", + ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)), + packet->src_port); + } + + if (rcode < 0) { /* error or connection reset */ + listener->status = RAD_LISTEN_STATUS_REMOVE_FD; + + /* + * Decrement the number of connections. + */ + if (sock->parent->num_connections > 0) { + sock->parent->num_connections--; + } + if (sock->client->num_connections > 0) { + sock->client->num_connections--; + } + + /* + * Tell the event handler that an FD has disappeared. + */ + DEBUG("Client has closed connection"); + event_new_fd(listener); + + /* + * Do NOT free the listener here. It's in use by + * a request, and will need to hang around until + * all of the requests are done. + * + * It is instead free'd in remove_from_request_hash() + */ + return 0; + } + + RAD_STATS_TYPE_INC(listener, total_requests); + + /* + * Some sanity checks, based on the packet code. + */ + switch(packet->code) { + case PW_AUTHENTICATION_REQUEST: + RAD_STATS_CLIENT_INC(listener, client, total_requests); + fun = rad_authenticate; + break; + + case PW_STATUS_SERVER: + if (!mainconfig.status_server) { + 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_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; + } /* 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(&sock->packet); + return 0; + } + + *pfun = fun; + sock->packet = NULL; /* we have no need for more partial reads */ + return 1; +} + +static int auth_tcp_accept(rad_listen_t *listener, + UNUSED RAD_REQUEST_FUNP *pfun, + UNUSED REQUEST **prequest) +{ + int newfd, src_port; + rad_listen_t *this; + socklen_t salen; + struct sockaddr_storage src; + listen_socket_t *sock; + fr_ipaddr_t src_ipaddr; + RADCLIENT *client; + + salen = sizeof(src); + + DEBUG2(" ... new connection request on TCP socket."); + + newfd = accept(listener->fd, (struct sockaddr *) &src, &salen); + if (newfd < 0) { + /* + * Non-blocking sockets must handle this. + */ + if (errno == EWOULDBLOCK) { + return 0; + } + + DEBUG2(" ... failed to accept connection."); + return -1; + } + + if (!fr_sockaddr2ipaddr(&src, salen, &src_ipaddr, &src_port)) { + DEBUG2(" ... unknown address family."); + return 0; + } + + /* + * Enforce client IP address checks on accept, not on + * every packet. + */ + if ((client = client_listener_find(listener, + &src_ipaddr, src_port)) == NULL) { + close(newfd); + RAD_STATS_TYPE_INC(listener, total_invalid_requests); + return 0; + } + + /* + * Enforce max_connectionsx on client && listen section. + */ + if ((client->max_connections != 0) && + (client->max_connections == client->num_connections)) { + /* + * FIXME: Print client IP/port, and server IP/port. + */ + radlog(L_INFO, "Ignoring new connection due to client max_connections (%d)", client->max_connections); + close(newfd); + return 0; + } + + sock = listener->data; + if ((sock->max_connections != 0) && + (sock->max_connections == sock->num_connections)) { + /* + * FIXME: Print client IP/port, and server IP/port. + */ + radlog(L_INFO, "Ignoring new connection due to socket max_connections"); + close(newfd); + return 0; + } + client->num_connections++; + sock->num_connections++; + + /* + * Add the new listener. + */ + this = listen_alloc(listener->type); + if (!this) return -1; + + /* + * Copy everything, including the pointer to the socket + * information. + */ + sock = this->data; + memcpy(this->data, listener->data, sizeof(*sock)); + memcpy(this, listener, sizeof(*this)); + this->next = NULL; + this->data = sock; /* fix it back */ + + sock->parent = listener->data; + sock->other_ipaddr = src_ipaddr; + sock->other_port = src_port; + sock->client = client; + + this->fd = newfd; + this->status = RAD_LISTEN_STATUS_INIT; + this->recv = auth_tcp_recv; + + /* + * FIXME: set O_NONBLOCK on the accept'd fd. + * See djb's portability rants for details. + */ + + /* + * Tell the event loop that we have a new FD. + * This can be called from a child thread... + */ + event_new_fd(this); + + return 0; +} +#endif + +/* + * This function is stupid and complicated. + */ static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize) { size_t len; @@ -440,25 +677,98 @@ 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); } + +#ifdef WITH_TCP + if (this->recv == auth_tcp_accept) { + ADDSTRING(" proto tcp"); + } +#endif + +#ifdef WITH_TCP + /* + * TCP sockets get printed a little differently, to make + * it clear what's going on. + */ + if (sock->client) { + ADDSTRING(" from client ("); + ip_ntoh(&sock->other_ipaddr, buffer, bufsize); + FORWARD; + + ADDSTRING(", "); + snprintf(buffer, bufsize, "%d", sock->other_port); + FORWARD; + ADDSTRING(") -> ("); + + if ((sock->my_ipaddr.af == AF_INET) && + (sock->my_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) { + strlcpy(buffer, "*", bufsize); + } else { + ip_ntoh(&sock->my_ipaddr, buffer, bufsize); + } + FORWARD; + + ADDSTRING(", "); + snprintf(buffer, bufsize, "%d", sock->my_port); + FORWARD; + + if (this->server) { + ADDSTRING(", virtual-server="); + ADDSTRING(this->server); + } + + ADDSTRING(")"); + + return 1; + } + + /* + * Maybe it's a socket that we opened to a home server. + */ + if ((sock->proto == IPPROTO_TCP) && + (this->type == RAD_LISTEN_PROXY)) { + ADDSTRING(" ("); + ip_ntoh(&sock->my_ipaddr, buffer, bufsize); + FORWARD; + + ADDSTRING(", "); + snprintf(buffer, bufsize, "%d", sock->my_port); + FORWARD; + ADDSTRING(") -> home_server ("); + + if ((sock->other_ipaddr.af == AF_INET) && + (sock->other_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) { + strlcpy(buffer, "*", bufsize); + } else { + ip_ntoh(&sock->other_ipaddr, buffer, bufsize); + } + FORWARD; + + ADDSTRING(", "); + snprintf(buffer, bufsize, "%d", sock->other_port); + FORWARD; + + ADDSTRING(")"); + + return 1; + } #endif ADDSTRING(" address "); - if ((sock->ipaddr.af == AF_INET) && - (sock->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) { + if ((sock->my_ipaddr.af == AF_INET) && + (sock->my_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) { strlcpy(buffer, "*", bufsize); } else { - ip_ntoh(&sock->ipaddr, buffer, bufsize); + ip_ntoh(&sock->my_ipaddr, buffer, bufsize); } FORWARD; ADDSTRING(" port "); - snprintf(buffer, bufsize, "%d", sock->port); + snprintf(buffer, bufsize, "%d", sock->my_port); FORWARD; if (this->server) { @@ -472,6 +782,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. @@ -519,19 +831,73 @@ static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this) return -1; } - sock->ipaddr = ipaddr; - sock->port = listen_port; + sock->proto = IPPROTO_UDP; + + if (cf_pair_find(cs, "proto")) { +#ifndef WITH_TCP + cf_log_err(cf_sectiontoitem(cs), + "System does not support the TCP protocol. Delete this line from the configuration file."); + return -1; +#else + char *proto = NULL; + + + rcode = cf_item_parse(cs, "proto", PW_TYPE_STRING_PTR, + &proto, "udp"); + if (rcode < 0) return -1; + + if (strcmp(proto, "udp") == 0) { + sock->proto = IPPROTO_UDP; + + } else if (strcmp(proto, "tcp") == 0) { + sock->proto = IPPROTO_TCP; + + rcode = cf_item_parse(cs, "max_connections", PW_TYPE_INTEGER, + &sock->max_connections, "64"); + if (rcode < 0) return -1; + + } else { + cf_log_err(cf_sectiontoitem(cs), + "Unknown proto name \"%s\"", proto); + free(proto); + return -1; + } + free(proto); + + /* + * TCP requires a destination IP for sockets. + * UDP doesn't, so it's allowed. + */ + 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 + } + + 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"); @@ -543,8 +909,42 @@ static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this) return -1; } sock->interface = value; + } + +#ifdef WITH_DHCP + /* + * If we can do broadcasts.. + */ + if (cf_pair_find(cs, "broadcast")) { +#ifndef SO_BROADCAST + cf_log_err(cf_sectiontoitem(cs), + "System does not support broadcast sockets. Delete this line from the configuration file."); + return -1; +#else + const char *value; + CONF_PAIR *cp = cf_pair_find(cs, "broadcast"); + + if (this->type != RAD_LISTEN_DHCP) { + cf_log_err(cf_pairtoitem(cp), + "Broadcast can only be set for DHCP listeners. Delete this line from the configuration file."); + return -1; + } + + rad_assert(cp != NULL); + value = cf_pair_value(cp); + if (!value) { + cf_log_err(cf_sectiontoitem(cs), + "No broadcast value given"); + return -1; + } + + /* + * Hack... whatever happened to cf_section_parse? + */ + sock->broadcast = (strcmp(value, "yes") == 0); #endif } +#endif /* * And bind it to the port. @@ -553,8 +953,8 @@ static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this) char buffer[128]; cf_log_err(cf_sectiontoitem(cs), "Error binding to port for %s port %d", - ip_ntoh(&sock->ipaddr, buffer, sizeof(buffer)), - sock->port); + ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)), + sock->my_port); return -1; } @@ -622,6 +1022,16 @@ static int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this) return -1; } +#ifdef WITH_TCP + if (sock->proto == IPPROTO_TCP) { + /* + * Re-write the listener receive function to + * allow us to accept the socket. + */ + this->recv = auth_tcp_accept; + } +#endif + return 0; } @@ -668,14 +1078,9 @@ static int acct_socket_send(rad_listen_t *listener, REQUEST *request) */ static int proxy_socket_send(rad_listen_t *listener, REQUEST *request) { - listen_socket_t *sock = listener->data; - rad_assert(request->proxy_listener == listener); rad_assert(listener->send == proxy_socket_send); - request->proxy->src_ipaddr = sock->ipaddr; - request->proxy->src_port = sock->port; - return rad_send(request->proxy, request->packet, request->home_server->secret); } @@ -940,9 +1345,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."); @@ -996,10 +1401,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; @@ -1047,7 +1452,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); /* @@ -1108,7 +1513,6 @@ static int coa_socket_recv(rad_listen_t *listener, int code, src_port; RADIUS_PACKET *packet; RAD_REQUEST_FUNP fun = NULL; - char buffer[128]; RADCLIENT *client; fr_ipaddr_t src_ipaddr; @@ -1126,24 +1530,8 @@ static int coa_socket_recv(rad_listen_t *listener, &src_ipaddr, src_port)) == NULL) { rad_recv_discard(listener->fd); RAD_STATS_TYPE_INC(listener, total_invalid_requests); - - if (debug_flag > 0) { - char name[1024]; - - listener->print(listener, name, sizeof(name)); - - /* - * This is debugging rather than logging, so that - * DoS attacks don't affect us. - */ - DEBUG("Ignoring request to %s from unknown client %s port %d", - name, - inet_ntop(src_ipaddr.af, &src_ipaddr.ipaddr, - buffer, sizeof(buffer)), src_port); - } - - return 0; - } + return 0; + } /* * Some sanity checks, based on the packet code. @@ -1262,6 +1650,82 @@ static int proxy_socket_recv(rad_listen_t *listener, return 1; } + +#ifdef WITH_TCP +/* + * Recieve packets from a proxy socket. + */ +static int proxy_socket_tcp_recv(rad_listen_t *listener, + RAD_REQUEST_FUNP *pfun, REQUEST **prequest) +{ + REQUEST *request; + RADIUS_PACKET *packet; + RAD_REQUEST_FUNP fun = NULL; + listen_socket_t *sock = listener->data; + char buffer[128]; + + packet = fr_tcp_recv(listener->fd, 0); + if (!packet) { + listener->status = RAD_LISTEN_STATUS_REMOVE_FD; + event_new_fd(listener); + return 0; + } + + /* + * FIXME: Client MIB updates? + */ + switch(packet->code) { + case PW_AUTHENTICATION_ACK: + case PW_ACCESS_CHALLENGE: + case PW_AUTHENTICATION_REJECT: + fun = rad_authenticate; + break; + +#ifdef WITH_ACCOUNTING + case PW_ACCOUNTING_RESPONSE: + fun = rad_accounting; + break; +#endif + + default: + /* + * FIXME: Update MIB for packet types? + */ + radlog(L_ERR, "Invalid packet code %d sent to a proxy port " + "from home server %s port %d - ID %d : IGNORED", + packet->code, + ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)), + packet->src_port, packet->id); + rad_free(&packet); + return 0; + } + + packet->src_ipaddr = sock->other_ipaddr; + packet->src_port = sock->other_port; + packet->dst_ipaddr = sock->my_ipaddr; + packet->dst_port = sock->my_port; + + /* + * FIXME: Have it return an indication of packets that + * are OK to ignore (dups, too late), versus ones that + * aren't OK to ignore (unknown response, spoofed, etc.) + * + * Close the socket on bad packets... + */ + request = received_proxy_response(packet); + if (!request) { + return 0; + } + + rad_assert(fun != NULL); + sock->opened = sock->last_packet = request->timestamp; + + *pfun = fun; + *prequest = request; + + return 1; +} +#endif #endif @@ -1368,7 +1832,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 @@ -1393,55 +1857,79 @@ static int listen_bind(rad_listen_t *this) struct sockaddr_storage salocal; socklen_t salen; listen_socket_t *sock = this->data; +#ifndef WITH_TCP +#define proto_for_port "udp" +#define sock_type SOCK_DGRAM +#else + const char *proto_for_port = "udp"; + int sock_type = SOCK_DGRAM; + + if (sock->proto == IPPROTO_TCP) { +#ifdef WITH_VMPS + if (this->type == RAD_LISTEN_VQP) { + radlog(L_ERR, "VQP does not support TCP transport"); + return -1; + } +#endif + + proto_for_port = "tcp"; + sock_type = SOCK_STREAM; + } +#endif /* * If the port is zero, then it means the appropriate * thing from /etc/services. */ - if (sock->port == 0) { + if (sock->my_port == 0) { struct servent *svp; switch (this->type) { case RAD_LISTEN_AUTH: - svp = getservbyname ("radius", "udp"); + svp = getservbyname ("radius", proto_for_port); if (svp != NULL) { - sock->port = ntohs(svp->s_port); + sock->my_port = ntohs(svp->s_port); } else { - sock->port = PW_AUTH_UDP_PORT; + sock->my_port = PW_AUTH_UDP_PORT; } break; #ifdef WITH_ACCOUNTING case RAD_LISTEN_ACCT: - svp = getservbyname ("radacct", "udp"); + svp = getservbyname ("radacct", proto_for_port); if (svp != NULL) { - sock->port = ntohs(svp->s_port); + sock->my_port = ntohs(svp->s_port); } else { - sock->port = PW_ACCT_UDP_PORT; + sock->my_port = PW_ACCT_UDP_PORT; } break; #endif #ifdef WITH_PROXY case RAD_LISTEN_PROXY: - sock->port = 0; + /* leave it at zero */ break; #endif #ifdef WITH_VMPS case RAD_LISTEN_VQP: - sock->port = 1589; + sock->my_port = 1589; break; #endif #ifdef WITH_COA case RAD_LISTEN_COA: - sock->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; } } @@ -1449,17 +1937,17 @@ static int listen_bind(rad_listen_t *this) /* * Copy fr_socket() here, as we may need to bind to a device. */ - this->fd = socket(sock->ipaddr.af, SOCK_DGRAM, 0); + this->fd = socket(sock->my_ipaddr.af, sock_type, 0); if (this->fd < 0) { radlog(L_ERR, "Failed opening socket: %s", strerror(errno)); 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); @@ -1473,9 +1961,60 @@ 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) { + int on = 1; + + if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + close(this->fd); + radlog(L_ERR, "Failed to reuse address: %s", strerror(errno)); + return -1; + } } #endif +#if defined(WITH_TCP) && defined(WITH_UDPFROMTO) + else /* UDP sockets get UDPfromto */ +#endif + #ifdef WITH_UDPFROMTO /* * Initialize udpfromto for all sockets. @@ -1485,17 +2024,17 @@ static int listen_bind(rad_listen_t *this) return -1; } #endif - + /* * Set up sockaddr stuff. */ - if (!fr_ipaddr2sockaddr(&sock->ipaddr, sock->port, &salocal, &salen)) { + if (!fr_ipaddr2sockaddr(&sock->my_ipaddr, sock->my_port, &salocal, &salen)) { close(this->fd); return -1; } #ifdef HAVE_STRUCT_SOCKADDR_IN6 - if (sock->ipaddr.af == AF_INET6) { + if (sock->my_ipaddr.af == AF_INET6) { /* * Listening on '::' does NOT get you IPv4 to * IPv6 mapping. You've got to listen on an IPv4 @@ -1504,7 +2043,7 @@ static int listen_bind(rad_listen_t *this) */ #ifdef IPV6_V6ONLY - if (IN6_IS_ADDR_UNSPECIFIED(&sock->ipaddr.ipaddr.ip6addr)) { + if (IN6_IS_ADDR_UNSPECIFIED(&sock->my_ipaddr.ipaddr.ip6addr)) { int on = 1; setsockopt(this->fd, IPPROTO_IPV6, IPV6_V6ONLY, @@ -1514,8 +2053,7 @@ static int listen_bind(rad_listen_t *this) } #endif /* HAVE_STRUCT_SOCKADDR_IN6 */ - - if (sock->ipaddr.af == AF_INET) { + if (sock->my_ipaddr.af == AF_INET) { UNUSED int flag; #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) @@ -1539,65 +2077,100 @@ static int listen_bind(rad_listen_t *this) #endif } - /* - * May be binding to priviledged ports. - */ - fr_suid_up(); - rcode = bind(this->fd, (struct sockaddr *) &salocal, salen); - fr_suid_down(); - if (rcode < 0) { - char buffer[256]; - close(this->fd); +#ifdef WITH_DHCP +#ifdef SO_BROADCAST + if (sock->broadcast) { + int on = 1; - this->print(this, buffer, sizeof(buffer)); - radlog(L_ERR, "Failed binding to %s: %s\n", - buffer, strerror(errno)); - return -1; + if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { + radlog(L_ERR, "Can't set broadcast option: %s\n", + strerror(errno)); + return -1; + } } - +#endif +#endif + /* - * FreeBSD jail issues. We bind to 0.0.0.0, but the - * kernel instead binds us to a 1.2.3.4. If this - * happens, notice, and remember our real IP. + * May be binding to priviledged ports. */ - { - struct sockaddr_storage src; - socklen_t sizeof_src = sizeof(src); + if (sock->my_port != 0) { +#ifdef SO_REUSEADDR + int on = 1; - memset(&src, 0, sizeof_src); - if (getsockname(this->fd, (struct sockaddr *) &src, - &sizeof_src) < 0) { - radlog(L_ERR, "Failed getting socket name: %s", + if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + radlog(L_ERR, "Can't set re-use address option: %s\n", strerror(errno)); return -1; } +#endif - if (!fr_sockaddr2ipaddr(&src, sizeof_src, - &sock->ipaddr, &sock->port)) { - radlog(L_ERR, "Socket has unsupported address family"); + fr_suid_up(); + rcode = bind(this->fd, (struct sockaddr *) &salocal, salen); + fr_suid_down(); + if (rcode < 0) { + char buffer[256]; + close(this->fd); + + this->print(this, buffer, sizeof(buffer)); + radlog(L_ERR, "Failed binding to %s: %s\n", + buffer, strerror(errno)); return -1; } + + /* + * FreeBSD jail issues. We bind to 0.0.0.0, but the + * kernel instead binds us to a 1.2.3.4. If this + * happens, notice, and remember our real IP. + */ + { + struct sockaddr_storage src; + socklen_t sizeof_src = sizeof(src); + + memset(&src, 0, sizeof_src); + if (getsockname(this->fd, (struct sockaddr *) &src, + &sizeof_src) < 0) { + radlog(L_ERR, "Failed getting socket name: %s", + strerror(errno)); + return -1; + } + + if (!fr_sockaddr2ipaddr(&src, sizeof_src, + &sock->my_ipaddr, &sock->my_port)) { + radlog(L_ERR, "Socket has unsupported address family"); + return -1; + } + } } -#ifdef O_NONBLOCK - { - int flags; - - if ((flags = fcntl(this->fd, F_GETFL, NULL)) < 0) { - radlog(L_ERR, "Failure getting socket flags: %s)\n", - strerror(errno)); - return -1; - } - - flags |= O_NONBLOCK; - if( fcntl(this->fd, F_SETFL, flags) < 0) { - radlog(L_ERR, "Failure setting socket flags: %s)\n", - strerror(errno)); +#ifdef WITH_TCP + if (sock->proto == IPPROTO_TCP) { + if (listen(this->fd, 8) < 0) { + close(this->fd); + radlog(L_ERR, "Failed in listen(): %s", strerror(errno)); return -1; } - } + } else #endif + if (fr_nonblock(this->fd) < 0) { + close(this->fd); + radlog(L_ERR, "Failed setting non-blocking on socket: %s", + strerror(errno)); + return -1; + } + + /* + * Mostly for proxy sockets. + */ + sock->other_ipaddr.af = sock->my_ipaddr.af; + +/* + * Don't screw up other people. + */ +#undef proto_for_port +#undef sock_type + return 0; } @@ -1668,7 +2241,6 @@ static rad_listen_t *listen_alloc(RAD_LISTEN_TYPE type) return this; } - #ifdef WITH_PROXY /* * Externally visible function for creating a new proxy LISTENER. @@ -1676,95 +2248,93 @@ static rad_listen_t *listen_alloc(RAD_LISTEN_TYPE type) * Not thread-safe, but all calls to it are protected by the * proxy mutex in event.c */ -rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr, int exists) +int proxy_new_listener(home_server *home, int src_port) { - int last_proxy_port, port; - rad_listen_t *this, *tmp, **last; - listen_socket_t *sock, *old; + rad_listen_t *this; + listen_socket_t *sock; - /* - * Find an existing proxy socket to copy. - */ - last_proxy_port = 0; - old = NULL; - last = &mainconfig.listen; - for (tmp = mainconfig.listen; tmp != NULL; tmp = tmp->next) { - /* - * Not proxy, ignore it. - */ - if (tmp->type != RAD_LISTEN_PROXY) continue; + if (!home) return 0; - sock = tmp->data; + if ((home->max_connections > 0) && + (home->num_connections >= home->max_connections)) { + DEBUG("WARNING: Home server has too many open connections (%d)", + home->max_connections); + return 0; + } - /* - * If we were asked to copy a specific one, do - * so. If we're just finding one that already - * exists, return a pointer to it. Otherwise, - * create ANOTHER one with the same IP address. - */ - if ((ipaddr->af != AF_UNSPEC) && - (fr_ipaddr_cmp(&sock->ipaddr, ipaddr) != 0)) { - if (exists) return tmp; - continue; - } - - if (sock->port > last_proxy_port) { - last_proxy_port = sock->port + 1; - } - if (!old) old = sock; + this = listen_alloc(RAD_LISTEN_PROXY); - last = &(tmp->next); - } + sock = this->data; + sock->other_ipaddr = home->ipaddr; + sock->other_port = home->port; + sock->home = home; + + sock->my_ipaddr = home->src_ipaddr; + sock->my_port = src_port; + sock->proto = home->proto; + +#ifdef WITH_TCP + sock->last_packet = time(NULL); + + if (home->proto == IPPROTO_TCP) { + this->recv = proxy_socket_tcp_recv; - if (!old) { /* - * The socket MUST already exist if we're binding - * to an address while proxying. + * FIXME: connect() is blocking! + * We do this with the proxy mutex locked, which may + * cause large delays! * - * If we're initializing the server, it's OK for the - * socket to NOT exist. + * http://www.developerweb.net/forum/showthread.php?p=13486 */ - if (!exists) return NULL; - - this = listen_alloc(RAD_LISTEN_PROXY); - - sock = this->data; - sock->ipaddr = *ipaddr; + this->fd = fr_tcp_client_socket(&home->src_ipaddr, + &home->ipaddr, home->port); + } else +#endif + this->fd = fr_socket(&home->src_ipaddr, src_port); - } else { - this = listen_alloc(RAD_LISTEN_PROXY); - - sock = this->data; - sock->ipaddr = old->ipaddr; + if (this->fd < 0) { + DEBUG("Failed opening client socket: %s", fr_strerror()); + listen_free(&this); + return 0; } /* - * Keep going until we find an unused port. + * Figure out which port we were bound to. */ - for (port = last_proxy_port; port < 64000; port++) { - int rcode; - - sock->port = port; - - rcode = listen_bind(this); - if (rcode < 0) { + if (sock->my_port == 0) { + struct sockaddr_storage src; + socklen_t sizeof_src = sizeof(src); + + memset(&src, 0, sizeof_src); + if (getsockname(this->fd, (struct sockaddr *) &src, + &sizeof_src) < 0) { + radlog(L_ERR, "Failed getting socket name: %s", + strerror(errno)); listen_free(&this); - return NULL; + return 0; } - /* - * Add the new listener to the list of - * listeners. - */ - *last = this; - return this; + if (!fr_sockaddr2ipaddr(&src, sizeof_src, + &sock->my_ipaddr, &sock->my_port)) { + radlog(L_ERR, "Socket has unsupported address family"); + listen_free(&this); + return 0; + } } - listen_free(&this); - return NULL; + /* + * Tell the event loop that we have a new FD + */ + if (!event_new_fd(this)) { + listen_free(&this); + return 0; + } + + return 1; } #endif + static const FR_NAME_NUMBER listen_compare[] = { #ifdef WITH_STATS { "status", RAD_LISTEN_NONE }, @@ -1824,7 +2394,7 @@ static rad_listen_t *listen_parse(CONF_SECTION *cs, const char *server) return NULL; } free(listen_type); - + /* * Allow listen sections in the default config to * refer to a server. @@ -1839,6 +2409,18 @@ static rad_listen_t *listen_parse(CONF_SECTION *cs, const char *server) if (rcode < 0) return NULL; } +#ifdef WITH_PROXY + /* + * We were passed a virtual server, so the caller is + * defining a proxy listener inside of a virtual server. + * This isn't allowed right now. + */ + else if (type == RAD_LISTEN_PROXY) { + radlog(L_ERR, "Error: listen type \"proxy\" Cannot appear in a virtual server section"); + return NULL; + } +#endif + /* * Set up cross-type data. */ @@ -1859,6 +2441,26 @@ static rad_listen_t *listen_parse(CONF_SECTION *cs, const char *server) return this; } +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; +} + /* * Generate a list of listeners. Takes an input list of * listeners, too, so we don't close sockets with waiting packets. @@ -1916,7 +2518,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 @@ -1929,8 +2531,8 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) sock = this->data; - sock->ipaddr = server_ipaddr; - sock->port = auth_port; + sock->my_ipaddr = server_ipaddr; + sock->my_port = auth_port; sock->clients = clients_parse_section(config); if (!sock->clients) { @@ -1942,11 +2544,11 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) if (listen_bind(this) < 0) { listen_free(head); - radlog(L_ERR, "There appears to be another RADIUS server running on the authentication port %d", sock->port); + radlog(L_ERR, "There appears to be another RADIUS server running on the authentication port %d", sock->my_port); listen_free(&this); return -1; } - auth_port = sock->port; /* may have been updated in listen_bind */ + auth_port = sock->my_port; /* may have been updated in listen_bind */ if (override) { cs = cf_section_sub_find_name2(config, "server", mainconfig.name); @@ -1960,7 +2562,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) /* * No acct for vmpsd */ - if (strcmp(progname, "vmpsd") == 0) goto do_proxy; + if (strcmp(progname, "vmpsd") == 0) goto add_sockets; #endif #ifdef WITH_ACCOUNTING @@ -1979,8 +2581,8 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) * The accounting port is always the * authentication port + 1 */ - sock->ipaddr = server_ipaddr; - sock->port = auth_port + 1; + sock->my_ipaddr = server_ipaddr; + sock->my_port = auth_port + 1; sock->clients = clients_parse_section(config); if (!sock->clients) { @@ -1992,7 +2594,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) 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); + radlog(L_ERR, "There appears to be another RADIUS server running on the accounting port %d", sock->my_port); return -1; } @@ -2021,7 +2623,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) cs = cf_section_sub_find_name2(config, "server", mainconfig.name); - if (!cs) goto do_proxy; + if (!cs) goto add_sockets; /* * Should really abstract this code... @@ -2035,15 +2637,11 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) return -1; } -#ifdef WITH_PROXY - if (this->type == RAD_LISTEN_PROXY) defined_proxy = 1; -#endif - *last = this; last = &(this->next); } /* loop over "listen" directives in server */ - goto do_proxy; + goto add_sockets; } /* @@ -2058,10 +2656,6 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) return -1; } -#ifdef WITH_PROXY - if (this->type == RAD_LISTEN_PROXY) defined_proxy = 1; -#endif - *last = this; last = &(this->next); } @@ -2086,36 +2680,53 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) return -1; } -#ifdef WITH_PROXY - 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; - } -#endif - *last = this; last = &(this->next); } /* loop over "listen" directives in virtual servers */ } /* loop over virtual servers */ +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. + */ + for (this = *head; this != NULL; this = this->next) { +#ifdef WITH_PROXY + if (this->type == RAD_LISTEN_PROXY) { + defined_proxy = 1; + } + +#endif + event_new_fd(this); + } + /* * If we're proxying requests, open the proxy FD. * Otherwise, don't do anything. */ - do_proxy: #ifdef WITH_PROXY - if (mainconfig.proxy_requests == TRUE) { - int port = -1; + if ((mainconfig.proxy_requests == TRUE) && + (*head != NULL) && !defined_proxy) { listen_socket_t *sock = NULL; + int port = 0; + home_server home; + + memset(&home, 0, sizeof(home)); /* - * No sockets to receive packets, therefore - * proxying is pointless. + * */ - if (!*head) return -1; - - if (defined_proxy) goto check_home_servers; + home.proto = IPPROTO_UDP; + home.src_ipaddr = server_ipaddr; /* * Find the first authentication port, @@ -2124,71 +2735,54 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head) 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; + + if (is_loopback(&sock->my_ipaddr)) continue; + + if (home.src_ipaddr.af == AF_UNSPEC) { + home.src_ipaddr = sock->my_ipaddr; } - port = sock->port + 2; /* skip acct port */ + port = sock->my_port + 2; break; } -#ifdef WITH_VMPS - if (this->type == RAD_LISTEN_VQP) { +#ifdef WITH_ACCT + if (this->type == RAD_LISTEN_ACCT) { sock = this->data; - if (server_ipaddr.af == AF_UNSPEC) { - server_ipaddr = sock->ipaddr; + + if (is_loopback(&sock->my_ipaddr)) continue; + + if (home.src_ipaddr.af == AF_UNSPEC) { + home.src_ipaddr = sock->my_ipaddr; } - port = sock->port + 1; + port = sock->my_port + 1; break; } #endif } - 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); + if (home.src_ipaddr.af == AF_UNSPEC) { + home.src_ipaddr.af = AF_INET; + /* everything else is already set to zero */ } - this = listen_alloc(RAD_LISTEN_PROXY); - sock = this->data; + home.ipaddr.af = home.src_ipaddr.af; + /* everything else is already set to zero */ - /* - * 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) { + if (!proxy_new_listener(&home, port)) { listen_free(head); - listen_free(&this); - radlog(L_ERR, "Failed to open socket for proxying"); return -1; } - - /* - * Create *additional* proxy listeners, based - * on their src_ipaddr. - */ - check_home_servers: - if (home_server_create_listeners(*head) != 0) return -1; } #endif + /* + * Haven't defined any sockets. Die. + */ + if (!*head) return -1; + + return 0; } @@ -2213,6 +2807,21 @@ void listen_free(rad_listen_t **head) if (master_listen[this->type].free) { master_listen[this->type].free(this); } + +#ifdef WITH_TCP + if ((this->type == RAD_LISTEN_AUTH) || +#ifdef WITH_ACCT + (this->type == RAD_LISTEN_ACCT) || +#endif +#ifdef WITH_PROXY + (this->type == RAD_LISTEN_PROXY) +#endif + ) { + listen_socket_t *sock = this->data; + rad_free(&sock->packet); + } +#endif + free(this->data); free(this); @@ -2236,8 +2845,8 @@ RADCLIENT_LIST *listener_find_client_list(const fr_ipaddr_t *ipaddr, sock = this->data; - if ((sock->port == port) && - (fr_ipaddr_cmp(ipaddr, &sock->ipaddr) == 0)) { + if ((sock->my_port == port) && + (fr_ipaddr_cmp(ipaddr, &sock->my_ipaddr) == 0)) { return sock->clients; } } @@ -2262,24 +2871,15 @@ rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port) sock = this->data; - if ((sock->port == port) && - (fr_ipaddr_cmp(ipaddr, &sock->ipaddr) == 0)) { + if ((sock->my_port == port) && + (fr_ipaddr_cmp(ipaddr, &sock->my_ipaddr) == 0)) { return this; } - if ((sock->port == port) && - ((sock->ipaddr.af == AF_INET) && - (sock->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY))) { + if ((sock->my_port == port) && + fr_inaddr_any(&sock->my_ipaddr)) { return this; } - -#ifdef HAVE_STRUCT_SOCKADDR_IN6 - if ((sock->port == port) && - (sock->ipaddr.af == AF_INET6) && - (IN6_IS_ADDR_UNSPECIFIED(&sock->ipaddr.ipaddr.ip6addr))) { - return this; - } -#endif } return NULL;