diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index da9f3cfbb..c299d7faf 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -738,15 +738,16 @@ radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *oserv, int sock, int sock6, int auth) { - struct sockaddr_in serv; + struct sockaddr_in serv, claddr; #ifdef CONFIG_IPV6 - struct sockaddr_in6 serv6; + struct sockaddr_in6 serv6, claddr6; #endif /* CONFIG_IPV6 */ struct sockaddr *addr; - socklen_t addrlen; + socklen_t addrlen, claddrlen; char abuf[50]; int sel_sock; struct radius_msg_list *entry; + struct hostapd_radius_servers *conf = radius->conf; hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, @@ -816,11 +817,64 @@ radius_change_server(struct radius_client_data *radius, return -1; } + if (conf->force_client_addr) { + switch (conf->client_addr.af) { + case AF_INET: + os_memset(&claddr, 0, sizeof(claddr)); + claddr.sin_family = AF_INET; + claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr; + claddr.sin_port = htons(0); + claddrlen = sizeof(claddr); + break; +#ifdef CONFIG_IPV6 + case AF_INET6: + os_memset(&claddr6, 0, sizeof(claddr6)); + claddr6.sin6_family = AF_INET6; + os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6, + sizeof(struct in6_addr)); + claddr6.sin6_port = htons(0); + claddrlen = sizeof(claddr6); + break; +#endif /* CONFIG_IPV6 */ + default: + return -1; + } + + if (bind(sel_sock, (struct sockaddr *) &claddr, claddrlen) < 0) + { + perror("bind[radius]"); + return -1; + } + } + if (connect(sel_sock, addr, addrlen) < 0) { perror("connect[radius]"); return -1; } +#ifndef CONFIG_NATIVE_WINDOWS + switch (nserv->addr.af) { + case AF_INET: + claddrlen = sizeof(claddr); + getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen); + wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", + inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); + break; +#ifdef CONFIG_IPV6 + case AF_INET6: { + claddrlen = sizeof(claddr6); + getsockname(sel_sock, (struct sockaddr *) &claddr6, + &claddrlen); + wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", + inet_ntop(AF_INET6, &claddr6.sin6_addr, + abuf, sizeof(abuf)), + ntohs(claddr6.sin6_port)); + break; + } +#endif /* CONFIG_IPV6 */ + } +#endif /* CONFIG_NATIVE_WINDOWS */ + if (auth) radius->auth_sock = sel_sock; else diff --git a/src/radius/radius_client.h b/src/radius/radius_client.h index fd5088b32..832a0a261 100644 --- a/src/radius/radius_client.h +++ b/src/radius/radius_client.h @@ -57,6 +57,9 @@ struct hostapd_radius_servers { int acct_interim_interval; int msg_dumps; + + struct hostapd_ip_addr client_addr; + int force_client_addr; }; diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index 7502a20f8..4d9678569 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -635,7 +635,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, static void wpa_init_conf(struct eapol_test_data *e, struct wpa_supplicant *wpa_s, const char *authsrv, - int port, const char *secret) + int port, const char *secret, + const char *cli_addr) { struct hostapd_radius_server *as; int res; @@ -671,6 +672,16 @@ static void wpa_init_conf(struct eapol_test_data *e, e->radius_conf->auth_server = as; e->radius_conf->auth_servers = as; e->radius_conf->msg_dumps = 1; + if (cli_addr) { + if (hostapd_parse_ip_addr(cli_addr, + &e->radius_conf->client_addr) == 0) + e->radius_conf->force_client_addr = 1; + else { + wpa_printf(MSG_ERROR, "Invalid IP address '%s'", + cli_addr); + assert(0); + } + } e->radius = radius_client_init(wpa_s, e->radius_conf); assert(e->radius != NULL); @@ -865,10 +876,10 @@ static void usage(void) { printf("usage:\n" "eapol_test [-nWS] -c [-a] [-p] " - "[-s] \\\n" + "[-s]\\\n" " [-r] [-t] [-C] \\\n" " [-M] \\\n" - " [-I] [-i]\n" + " [-I] [-i] [-A]\n" "eapol_test scard\n" "eapol_test sim [debug]\n" "\n"); @@ -880,6 +891,8 @@ static void usage(void) "default 1812\n" " -s = shared secret with the authentication " "server, default 'radius'\n" + " -A = IP address of the client, default: select " + "automatically\n" " -r = number of re-authentications\n" " -W = wait for a control interface monitor before starting\n" " -S = save configuration after authentiation\n" @@ -903,6 +916,7 @@ int main(int argc, char *argv[]) char *as_addr = "127.0.0.1"; int as_port = 1812; char *as_secret = "radius"; + char *cli_addr = NULL; char *conf = NULL; int timeout = 30; @@ -919,13 +933,16 @@ int main(int argc, char *argv[]) wpa_debug_show_keys = 1; for (;;) { - c = getopt(argc, argv, "a:c:C:iI:M:np:r:s:St:W"); + c = getopt(argc, argv, "a:A:c:C:iI:M:np:r:s:St:W"); if (c < 0) break; switch (c) { case 'a': as_addr = optarg; break; + case 'A': + cli_addr = optarg; + break; case 'c': conf = optarg; break; @@ -1009,7 +1026,8 @@ int main(int argc, char *argv[]) return -1; } - wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret); + wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret, + cli_addr); wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); if (wpa_s.ctrl_iface == NULL) { printf("Failed to initialize control interface '%s'.\n"