Browse Source

Disable PMTU discovery for RADIUS packets (sent them without DF)

When Linux has Path MTU discovery enabled, it sets by default the DF bit
on all outgoing datagrams, also UDP ones. If a RADIUS message is bigger
than the smallest MTU size to the target, it will be discarded.

This effectively limits RADIUS messages to ~ 1500 Bytes, while they can
be up to 4k according to RFC2865. In practice, this can mean trouble
when doing EAP-TLS with many RADIUS attributes besides the EAP-Message.
[Bug 326]
Stefan Winter 15 years ago
parent
commit
a2fbf12524
1 changed files with 22 additions and 2 deletions
  1. 22 2
      src/radius/radius_client.c

+ 22 - 2
src/radius/radius_client.c

@@ -917,6 +917,22 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static int radius_client_disable_pmtu_discovery(int s)
+{
+	int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
+	int action = IP_PMTUDISC_DONT;
+	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+		       sizeof(action));
+	if (r == -1)
+		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
+			   "%s", strerror(errno));
+#endif
+	return r;
+}
+
+
 static int radius_client_init_auth(struct radius_client_data *radius)
 {
 	struct hostapd_radius_servers *conf = radius->conf;
@@ -925,8 +941,10 @@ static int radius_client_init_auth(struct radius_client_data *radius)
 	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->auth_serv_sock < 0)
 		perror("socket[PF_INET,SOCK_DGRAM]");
-	else
+	else {
+		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
 		ok++;
+	}
 
 #ifdef CONFIG_IPV6
 	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -975,8 +993,10 @@ static int radius_client_init_acct(struct radius_client_data *radius)
 	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (radius->acct_serv_sock < 0)
 		perror("socket[PF_INET,SOCK_DGRAM]");
-	else
+	else {
+		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
 		ok++;
+	}
 
 #ifdef CONFIG_IPV6
 	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);