Browse Source

eapol_test: Allow client IP address to be specified

Allow the user to set the IP address of the eapol_test client. This if
very useful when you have a machine with many interfaces and want to use a
particular one for testing RADIUS connectivity. For instance when I run the
national eduroam proxy I can only connect to other server from a particular
address, an our machine happens to have several IPs. So if I want to run
connectivity tests, I must make sure that my test uses a particular
interface. The -A option allows one to set this).

(jm: cleaned up to use radius configuration structure instead of global
variable for the address and added IPv6 support)
Tomasz Wolniewicz 17 years ago
parent
commit
c454f57379
3 changed files with 83 additions and 8 deletions
  1. 57 3
      src/radius/radius_client.c
  2. 3 0
      src/radius/radius_client.h
  3. 23 5
      wpa_supplicant/eapol_test.c

+ 57 - 3
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

+ 3 - 0
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;
 };
 
 

+ 23 - 5
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<conf> [-a<AS IP>] [-p<AS port>] "
-	       "[-s<AS secret>] \\\n"
+	       "[-s<AS secret>]\\\n"
 	       "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
 	       "           [-M<client MAC address>] \\\n"
-	       "           [-I<CUI>] [-i]\n"
+	       "           [-I<CUI>] [-i] [-A<client IP>]\n"
 	       "eapol_test scard\n"
 	       "eapol_test sim <PIN> <num triplets> [debug]\n"
 	       "\n");
@@ -880,6 +891,8 @@ static void usage(void)
 	       "default 1812\n"
 	       "  -s<AS secret> = shared secret with the authentication "
 	       "server, default 'radius'\n"
+	       "  -A<client IP> = IP address of the client, default: select "
+	       "automatically\n"
 	       "  -r<count> = 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"