Allow IPv6 to bind to interface with scope.
authorAlan T. DeKok <aland@freeradius.org>
Sat, 6 Mar 2010 14:45:08 +0000 (15:45 +0100)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 6 Mar 2010 20:20:10 +0000 (21:20 +0100)
A follow-on to the previous patch.

src/main/listen.c

index f4e9921..3b5d745 100644 (file)
@@ -460,11 +460,6 @@ int listen_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
         *      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");
 
@@ -476,7 +471,6 @@ int listen_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
                        return -1;
                }
                sock->interface = value;
-#endif
        }
 
 #ifdef WITH_DHCP
@@ -675,7 +669,12 @@ static int listen_bind(rad_listen_t *this)
 
 #ifdef WITH_COA
                case RAD_LISTEN_COA:
-                       sock->my_port = PW_COA_UDP_PORT;
+                       svp = getservbyname ("radius-dynauth", "udp");
+                       if (svp != NULL) {
+                               sock->port = ntohs(svp->s_port);
+                       } else {
+                               sock->port = PW_COA_UDP_PORT;
+                       }
                        break;
 #endif
                default:
@@ -693,11 +692,11 @@ static int listen_bind(rad_listen_t *this)
                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);
 
@@ -711,8 +710,43 @@ 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->ipaddr.af == AF_INET6) {
+                       if (sock->ipaddr.scope == 0) {
+                               sock->ipaddr.scope = if_nametoindex(sock->interface);
+                               if (sock->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) {