From: Alan T. DeKok Date: Wed, 2 Sep 2015 20:46:08 +0000 (-0400) Subject: Port fixes from v3.1.x X-Git-Tag: release_3_0_10~173 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5a806d0bd3439b32e089dd2a12b8d0fb53572b2b;p=thirdparty%2Ffreeradius-server.git Port fixes from v3.1.x --- diff --git a/src/modules/proto_dhcp/dhcpclient.c b/src/modules/proto_dhcp/dhcpclient.c index 76e5e0ab931..5c923f136d3 100644 --- a/src/modules/proto_dhcp/dhcpclient.c +++ b/src/modules/proto_dhcp/dhcpclient.c @@ -26,7 +26,6 @@ RCSID("$Id$") #include #include -#include #include #ifdef WITH_DHCP @@ -46,26 +45,15 @@ static int retries = 3; static float timeout = 5.0; static struct timeval tv_timeout; -static uint16_t server_port = 0; -static int packet_code = 0; -static fr_ipaddr_t server_ipaddr; - -static fr_ipaddr_t client_ipaddr; -static uint16_t client_port = 0; - static int sockfd; -#ifdef HAVE_LINUX_IF_PACKET_H -struct sockaddr_ll ll; /* Socket address structure */ static char *iface = NULL; static int iface_ind = -1; -# define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log -#endif - -static RADIUS_PACKET *request = NULL; static RADIUS_PACKET *reply = NULL; +static bool reply_expected = true; + #define DHCP_CHADDR_LEN (16) #define DHCP_SNAME_LEN (64) #define DHCP_FILE_LEN (128) @@ -102,9 +90,7 @@ static void NEVER_RETURNS usage(void) fprintf(stderr, " -d Set the directory where the dictionaries are stored (defaults to " RADDBDIR ").\n"); fprintf(stderr, " -D Set main dictionary directory (defaults to " DICTDIR ").\n"); fprintf(stderr, " -f Read packets from file, not stdin.\n"); -#ifdef HAVE_LINUX_IF_PACKET_H fprintf(stderr, " -i Use this interface to send/receive at packet level on a raw socket.\n"); -#endif fprintf(stderr, " -t Wait 'timeout' seconds for a reply (may be a floating point number).\n"); fprintf(stderr, " -v Show program version information.\n"); fprintf(stderr, " -x Debugging mode.\n"); @@ -116,12 +102,13 @@ static void NEVER_RETURNS usage(void) /* * Initialize the request. */ -static int request_init(char const *filename) +static RADIUS_PACKET *request_init(char const *filename) { FILE *fp; vp_cursor_t cursor; VALUE_PAIR *vp; bool filedone = false; + RADIUS_PACKET *request; /* * Determine where to read the VP's from. @@ -129,16 +116,14 @@ static int request_init(char const *filename) if (filename) { fp = fopen(filename, "r"); if (!fp) { - fprintf(stderr, "dhcpclient: Error opening %s: %s\n", - filename, fr_syserror(errno)); - return 0; + fprintf(stderr, "dhcpclient: Error opening %s: %s\n", filename, fr_syserror(errno)); + return NULL; } } else { fp = stdin; } request = rad_alloc(NULL, false); - /* * Read the VP's. */ @@ -146,23 +131,21 @@ static int request_init(char const *filename) fr_perror("dhcpclient"); rad_free(&request); if (fp != stdin) fclose(fp); - return 1; + return NULL; } /* * Fix / set various options */ - for (vp = fr_cursor_init(&cursor, &request->vps); vp; vp = fr_cursor_next(&cursor)) { - + for (vp = fr_cursor_init(&cursor, &request->vps); + vp; + vp = fr_cursor_next(&cursor)) { + /* + * Allow to set packet type using DHCP-Message-Type + */ if (vp->da->vendor == DHCP_MAGIC_VENDOR && vp->da->attr == PW_DHCP_MESSAGE_TYPE) { - /* Allow to set packet type using DHCP-Message-Type. */ request->code = vp->vp_integer + PW_DHCP_OFFSET; - } else if (!vp->da->vendor) switch (vp->da->attr) { - - default: - break; - /* * Allow it to set the packet type in * the attributes read from the file. @@ -203,21 +186,19 @@ static int request_init(char const *filename) request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->src_ipaddr.prefix = 128; break; + + default: + break; } /* switch over the attribute */ } /* loop over the VP's we read in */ - - /* - * Use the default set on the command line - */ - if (!request->code) request->code = packet_code; if (fp != stdin) fclose(fp); /* * And we're done. */ - return 1; + return request; } static char const *dhcp_header_names[] = { @@ -306,119 +287,59 @@ static void print_hex(RADIUS_PACKET *packet) fflush(stdout); } -#ifdef HAVE_LINUX_IF_PACKET_H -/* - * Loop waiting for DHCP replies until timer expires. - * Note that there may be more than one reply: multiple DHCP servers can respond to a broadcast discover. - * A real client would pick one of the proposed replies. - * We'll just return the first eligible reply, and display the others. - */ -static RADIUS_PACKET *fr_dhcp_recv_raw_loop(int lsockfd, struct sockaddr_ll *p_ll, RADIUS_PACKET *request_p) +static void send_with_socket(RADIUS_PACKET *request) { - struct timeval tval; - RADIUS_PACKET *reply_p = NULL; - RADIUS_PACKET *cur_reply_p = NULL; - int nb_reply = 0; - int nb_offer = 0; - dc_offer_t *offer_list = NULL; - fd_set read_fd; - int retval; - - memcpy(&tval, &tv_timeout, sizeof(struct timeval)); - - /* Loop waiting for DHCP replies until timer expires */ - while (timerisset(&tval)) { - if ((!reply_p) || (cur_reply_p)) { // only debug at start and each time we get a valid DHCP reply on raw socket - DEBUG("Waiting for%sDHCP replies for: %d.%06d\n", - (nb_reply>0)?" additional ":" ", (int)tval.tv_sec, (int)tval.tv_usec); - } + sockfd = fr_socket(&request->src_ipaddr, request->src_port); + if (sockfd < 0) { + fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror()); + fr_exit_now(1); + } - cur_reply_p = NULL; - FD_ZERO(&read_fd); - FD_SET(lsockfd, &read_fd); - retval = select(lsockfd + 1, &read_fd, NULL, NULL, &tval); + /* + * Set option 'receive timeout' on socket. + * Note: in case of a timeout, the error will be "Resource temporarily unavailable". + */ + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv_timeout,sizeof(struct timeval)) == -1) { + fprintf(stderr, "dhcpclient: failed setting socket timeout: %s\n", + fr_syserror(errno)); + fr_exit_now(1); + } - if (retval < 0) { - fr_strerror_printf("Select on DHCP socket failed: %s", fr_syserror(errno)); - return NULL; - } + request->sockfd = sockfd; - if ( retval > 0 && FD_ISSET(lsockfd, &read_fd)) { - /* There is something to read on our socket */ - cur_reply_p = fr_dhcp_recv_raw_packet(lsockfd, p_ll, request_p); - } - - if (cur_reply_p) { - nb_reply ++; - - if (fr_debug_lvl) print_hex(cur_reply_p); - - if (fr_dhcp_decode(cur_reply_p) < 0) { - fprintf(stderr, "dhcpclient: failed decoding reply\n"); - return NULL; - } - - if (!reply_p) reply_p = cur_reply_p; - - if (cur_reply_p->code == PW_DHCP_OFFER) { - VALUE_PAIR *vp1 = fr_pair_find_by_num(cur_reply_p->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */ - VALUE_PAIR *vp2 = fr_pair_find_by_num(cur_reply_p->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-address */ - - if (vp1 && vp2) { - nb_offer ++; - offer_list = talloc_realloc(request_p, offer_list, dc_offer_t, nb_offer); - offer_list[nb_offer-1].server_addr = vp1->vp_ipaddr; - offer_list[nb_offer-1].offered_addr = vp2->vp_ipaddr; - } - } - } - } - - if (0 == nb_reply) { - fr_strerror_printf("No valid DHCP reply received"); - return NULL; + if (fr_dhcp_send(request) < 0) { + fprintf(stderr, "dhcpclient: failed sending: %s\n", + fr_syserror(errno)); + fr_exit_now(1); } - - /* display offer(s) received */ - if (nb_offer > 0 ) { - DEBUG("Received %d DHCP Offer(s):\n", nb_offer); - int i; - for (i=0; i= sizeof(buffer)) { - usage(); - } - - memcpy(buffer, argv[1] + 1, p - argv[1] - 1); - buffer[p - argv[1] - 1] = '\0'; - - hostname = buffer; - portname = p + 1; - - } - p = strchr(portname, ':'); - if (p && (strchr(p + 1, ':') == NULL)) { - *p = '\0'; - portname = p + 1; - } else { - portname = NULL; + if (ip_hton(&server_ipaddr, AF_INET, argv[1], false) < 0) { + fr_perror("dhcpclient"); + fr_exit_now(1); } - - if (ip_hton(&server_ipaddr, AF_INET, hostname, false) < 0) { - fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno)); - exit(1); - } - - /* - * Strip port from hostname if needed. - */ - if (portname) server_port = atoi(portname); + client_ipaddr.af = server_ipaddr.af; } /* @@ -547,145 +436,69 @@ int main(int argc, char **argv) } if (!server_port) server_port = 67; - request_init(filename); - - /* - * No data read. Die. - */ - if (!request || !request->vps) { - fprintf(stderr, "dhcpclient: Nothing to send.\n"); - exit(1); - } - - /* - * Sanity check. - */ - if (!request->code) { - fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n", - (argc >= 3) ? "'auto'" : "unspecified"); - exit(1); - } - - if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) { - /* These kind of packets do not get a reply, so don't wait for one. */ - reply_expected = false; - } - /* - * Always true for DHCP + * set "raw mode" if an interface is specified and if destination + * IP address is the broadcast address. */ - client_port = server_port + 1; - - /* - * Bind to the first specified IP address and port. - * This means we ignore later ones. - */ - if (request->src_ipaddr.af == AF_UNSPEC) { - memset(&client_ipaddr, 0, sizeof(client_ipaddr)); - client_ipaddr.af = server_ipaddr.af; - } else { - client_ipaddr = request->src_ipaddr; - } - - /* set "raw mode" if an interface is specified and if destination IP address is the broadcast address. */ -#ifdef HAVE_LINUX_IF_PACKET_H if (iface) { iface_ind = if_nametoindex(iface); if (iface_ind <= 0) { fprintf(stderr, "dhcpclient: unknown interface: %s\n", iface); - exit(1); + fr_exit_now(1); } if (server_ipaddr.ipaddr.ip4addr.s_addr == 0xFFFFFFFF) { - DEBUG("dhcpclient: Using interface: %s (index: %d) in raw packet mode\n", iface, iface_ind); - raw_mode = true; + fprintf(stderr, "dhcpclient: Sending broadcast packets is not supported\n"); + exit(1); } } - if (raw_mode) { - sockfd = fr_socket_packet(iface_ind, &ll); - } else -#endif - - { - sockfd = fr_socket(&client_ipaddr, client_port); + request = request_init(filename); + if (!request || !request->vps) { + fprintf(stderr, "dhcpclient: Nothing to send.\n"); + fr_exit_now(1); } - if (sockfd < 0) { - fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror()); - exit(1); - } + /* + * Set defaults if they weren't specified via pairs + */ + if (request->src_port == 0) request->src_port = server_port + 1; + if (request->dst_port == 0) request->dst_port = server_port; + if (request->src_ipaddr.af == AF_UNSPEC) request->src_ipaddr = client_ipaddr; + if (request->dst_ipaddr.af == AF_UNSPEC) request->dst_ipaddr = server_ipaddr; + if (!request->code) request->code = packet_code; /* - * Set option 'receive timeout' on socket. - * Note: in case of a timeout, the error will be "Resource temporarily unavailable". + * Sanity check. */ - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv_timeout,sizeof(struct timeval)) == -1) { - fprintf(stderr, "dhcpclient: failed setting socket timeout: %s\n", - fr_syserror(errno)); + if (!request->code) { + fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n", + (argc >= 3) ? "'auto'" : "unspecified"); exit(1); } - request->sockfd = sockfd; - if (request->src_ipaddr.af == AF_UNSPEC) { - request->src_ipaddr = client_ipaddr; - request->src_port = client_port; - } - if (request->dst_ipaddr.af == AF_UNSPEC) { - request->dst_ipaddr = server_ipaddr; - request->dst_port = server_port; + if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) { + /* These kind of packets do not get a reply, so don't wait for one. */ + reply_expected = false; } - /* * Encode the packet */ if (fr_dhcp_encode(request) < 0) { - fprintf(stderr, "dhcpclient: failed encoding: %s\n", - fr_strerror()); - exit(1); + fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror()); + fr_exit_now(1); } if (fr_debug_lvl) print_hex(request); -#ifdef HAVE_LINUX_IF_PACKET_H - if (raw_mode) { - if (fr_dhcp_send_raw_packet(sockfd, &ll, request) < 0) { - fprintf(stderr, "dhcpclient: failed sending (fr_dhcp_send_raw_packet): %s\n", - fr_syserror(errno)); - exit(1); - } - - if (!reply_expected) goto done; - - reply = fr_dhcp_recv_raw_loop(sockfd, &ll, request); - if (!reply) { - fprintf(stderr, "dhcpclient: Error receiving reply (fr_dhcp_recv_raw_loop)\n"); - exit(1); - } - } else -#endif - { - if (fr_dhcp_send(request) < 0) { - fprintf(stderr, "dhcpclient: failed sending: %s\n", - fr_syserror(errno)); - exit(1); - } - - if (!reply_expected) goto done; + send_with_socket(request); - reply = fr_dhcp_recv(sockfd); - if (!reply) { - fprintf(stderr, "dhcpclient: Error receiving reply %s\n", fr_strerror()); - exit(1); - } - if (fr_debug_lvl) print_hex(reply); + if (reply && fr_debug_lvl) print_hex(reply); - if (fr_dhcp_decode(reply) < 0) { - fprintf(stderr, "dhcpclient: failed decoding\n"); - return 1; - } + if (reply && fr_dhcp_decode(reply) < 0) { + fprintf(stderr, "dhcpclient: failed decoding\n"); + return 1; } -done: dict_free(); if (success) return 0;