Index: Makefile =================================================================== --- Makefile +++ Makefile @@ -34,6 +33,13 @@ SHLIB_MAJOR= 4 MAN= libradius.3 radius.conf.5 +.if ${MK_INET6_SUPPORT} != "no" +CFLAGS+= -DINET6 +.endif +.if ${MK_INET_SUPPORT} != "no" +CFLAGS+= -DINET +.endif + MLINKS+=libradius.3 rad_acct_open.3 \ libradius.3 rad_add_server.3 \ libradius.3 rad_add_server_ex.3 \ Index: libradius.3 =================================================================== --- libradius.3 +++ libradius.3 @@ -39,6 +39,8 @@ .Fn rad_add_server "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries" .Ft int .Fn rad_add_server_ex "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries" "int dead_time" "struct in_addr *bindto" +.Ft int +.Fn rad_add_server_bindto "struct rad_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int max_tries" "int dead_time" "const struct sockaddr *bindto" .Ft "struct rad_handle *" .Fn rad_auth_open "void" .Ft void @@ -95,6 +97,8 @@ .Fn rad_server_secret "struct rad_handle *h" .Ft "void" .Fn rad_bind_to "struct rad_handle *h" "in_addr_t addr" +.Ft "void" +.Fn rad_set_bindto "struct rad_handle *h" "const struct sockaddr *addr" .Ft u_char * .Fn rad_demangle "struct rad_handle *h" "const void *mangled" "size_t mlen" .Ft u_char * @@ -155,16 +159,37 @@ returns 0 on success, or \-1 if an error occurs. .Pp The library can also be configured programmatically by calls to -.Fn rad_add_server +.Fn rad_add_server , +.Fn rad_add_server_ex or -.Fn rad_add_server_ex . +.Fn rad_add_server_bindto . .Fn rad_add_server -is a backward compatible function, implemented via -.Fn rad_add_server_ex . +and +.Fn rad_add_server_ex +are backward compatible functions that support only IPv4 protocol and are +implemented via +.Fn rad_add_server_bindto +function. The .Fa host parameter specifies the server host, either as a fully qualified -domain name or as a dotted-quad IP address in text form. +domain name or as a IP address in text form (both IPv4 and IPv6). +If the +.Fa host +resolves to multiple IP addresses, the +.Fn rad_add_server_bindto +function will create multiple server structures. +If the +.Fa bindto +argument is +.No non- Ns Dv NULL , +the function will only lookup DNS entries in the same protocol family as the +.Fa bindto . +If the +.Fa bindto +argument is +.Dv NULL , +the function will only use both IPv4 and IPv6 entries. The .Fa port parameter specifies the UDP port to contact on the server. @@ -202,12 +227,17 @@ .Fa bindto parameter is an IP address on the multihomed host that is used as a source address for all requests. +The +.Fa bindto +parameter can be +.Dv NULL . .Fn rad_add_server returns 0 on success, or \-1 if an error occurs. .Pp -.Fn rad_add_server -or +.Fn rad_add_server , .Fn rad_add_server_ex +and +.Fn rad_add_server_bindto may be called multiple times, and they may be used together with .Fn rad_config . At most 10 servers may be specified. @@ -218,8 +248,7 @@ .Ss Creating a RADIUS Request A RADIUS request consists of a code specifying the kind of request, and zero or more attributes which provide additional information. -To -begin constructing a new request, call +To begin constructing a new request, call .Fn rad_create_request . In addition to the usual .Vt "struct rad_handle *" , @@ -446,8 +475,13 @@ returns the secret shared with the current RADIUS server according to the supplied rad_handle. .Pp +.Fn rad_bind_to +is a backward compatible function that supports only IPv4 protocol and is +implemented via +.Fn rad_set_bindto +function. The -.Fn rad_bind_to +.Fn rad_set_bindto assigns a source address for all requests to the current RADIUS server. .Pp The @@ -513,6 +547,10 @@ .It .Fn rad_add_server .It +.Fn rad_add_server_ex +.It +.Fn rad_add_server_bindto +.It .Fn rad_config .It .Fn rad_create_request @@ -606,9 +644,10 @@ .Fx project by Juniper Networks, Inc. .An Oleg Semyonov -subsequently added the ability to perform RADIUS -accounting. +subsequently added the ability to perform RADIUS accounting. Later additions and changes by .An Michael Bretterklieber . Server mode support was added by .An Alexander Motin . +IPv6 support was implemented by +.An Pawel Jakub Dawidek . Index: radlib.h =================================================================== --- radlib.h +++ radlib.h @@ -190,25 +188,39 @@ #define RAD_ERROR_CAUSE 101 /* Integer */ struct rad_handle; +struct sockaddr; struct timeval; __BEGIN_DECLS struct rad_handle *rad_acct_open(void); int rad_add_server(struct rad_handle *, const char *, int, const char *, int, int); +#ifdef INET int rad_add_server_ex(struct rad_handle *, const char *, int, const char *, int, int, int, struct in_addr *); +#endif +int rad_add_server_bindto(struct rad_handle *, const char *, + int, const char *, int, int, int, + const struct sockaddr *); struct rad_handle *rad_auth_open(void); +#ifdef INET void rad_bind_to(struct rad_handle *, in_addr_t); +#endif +void rad_set_bindto(struct rad_handle *h, + const struct sockaddr *addr); void rad_close(struct rad_handle *); int rad_config(struct rad_handle *, const char *); int rad_continue_send_request(struct rad_handle *, int, int *, struct timeval *); int rad_create_request(struct rad_handle *, int); int rad_create_response(struct rad_handle *, int); +#ifdef INET struct in_addr rad_cvt_addr(const void *); +#endif +#ifdef INET6 struct in6_addr rad_cvt_addr6(const void *); +#endif u_int32_t rad_cvt_int(const void *); char *rad_cvt_string(const void *, size_t); int rad_get_attr(struct rad_handle *, const void **, @@ -216,8 +228,12 @@ int rad_init_send_request(struct rad_handle *, int *, struct timeval *); struct rad_handle *rad_open(void); /* Deprecated, == rad_auth_open */ +#ifdef INET int rad_put_addr(struct rad_handle *, int, struct in_addr); +#endif +#ifdef INET6 int rad_put_addr6(struct rad_handle *, int, struct in6_addr); +#endif int rad_put_attr(struct rad_handle *, int, const void *, size_t); int rad_put_int(struct rad_handle *, int, u_int32_t); Index: radlib.c =================================================================== --- radlib.c +++ radlib.c @@ -50,9 +48,11 @@ /* We need the MPPE_KEY_LEN define */ #include +#include #include #include #include +#include #include #include #include @@ -68,7 +68,7 @@ static void insert_request_authenticator(struct rad_handle *, int); static void insert_message_authenticator(struct rad_handle *, int); static int is_valid_response(struct rad_handle *, int, - const struct sockaddr_in *); + const struct sockaddr *); static int put_password_attr(struct rad_handle *, int, const void *, size_t); static int put_raw_attr(struct rad_handle *, int, @@ -182,8 +182,7 @@ * specified server. */ static int -is_valid_response(struct rad_handle *h, int srv, - const struct sockaddr_in *from) +is_valid_response(struct rad_handle *h, int srv, const struct sockaddr *from) { MD5_CTX ctx; unsigned char md5[MD5_DIGEST_LENGTH]; @@ -199,9 +198,8 @@ srvp = &h->servers[srv]; /* Check the source address */ - if (from->sin_family != srvp->addr.sin_family || - from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr || - from->sin_port != srvp->addr.sin_port) + if (from->sa_family != srvp->addr.ss_family || + memcmp(from, &srvp->addr, from->sa_len) != 0) return 0; /* Check the message length */ @@ -383,65 +381,168 @@ rad_add_server(struct rad_handle *h, const char *host, int port, const char *secret, int timeout, int tries) { - struct in_addr bindto; - bindto.s_addr = INADDR_ANY; - return rad_add_server_ex(h, host, port, secret, timeout, tries, - DEAD_TIME, &bindto); + return rad_add_server_bindto(h, host, port, secret, timeout, tries, + DEAD_TIME, NULL); } +#ifdef INET int rad_add_server_ex(struct rad_handle *h, const char *host, int port, const char *secret, int timeout, int tries, int dead_time, struct in_addr *bindto) { + struct sockaddr_in sin; + struct sockaddr *sa; + + if (bindto == NULL) { + sa = NULL; + } else { + memset(&sin, 0, sizeof sin); + sin.sin_len = sizeof sin; + sin.sin_family = AF_INET; + sin.sin_port = 0; + memcpy(&sin.sin_addr, bindto, sizeof(sin.sin_addr)); + sa = (struct sockaddr *)&sin; + } + + return rad_add_server_bindto(h, host, port, secret, timeout, tries, + dead_time, sa); +} +#endif + +static void +server_bindto(struct rad_server *srvp, sa_family_t family, + const struct sockaddr *bindto) +{ +#ifdef INET + struct sockaddr_in sin; +#endif +#ifdef INET6 + struct sockaddr_in6 sin6; +#endif + +#if defined(INET) && defined(INET6) + assert(family == AF_INET || family == AF_INET6); +#elif defined(INET) + assert(family == AF_INET); +#elif defined(INET6) + assert(family == AF_INET6); +#endif + + if (bindto == NULL) { +#ifdef INET + if (family == AF_INET) { + memset(&sin, 0, sizeof sin); + sin.sin_len = sizeof sin; + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + bindto = (struct sockaddr *)&sin; + } +#endif +#ifdef INET6 + if (family == AF_INET6) { + memset(&sin6, 0, sizeof sin6); + sin6.sin6_len = sizeof sin6; + sin6.sin6_family = AF_INET6; + sin6.sin6_port = 0; + sin6.sin6_addr = in6addr_any; + bindto = (struct sockaddr *)&sin6; + } +#endif + } + + assert(family == bindto->sa_family); + + memset(&srvp->bindto, 0, sizeof(srvp->bindto)); + memcpy(&srvp->bindto, bindto, bindto->sa_len); +} + +int +rad_add_server_bindto(struct rad_handle *h, const char *host, int port, + const char *secret, int timeout, int tries, int dead_time, + const struct sockaddr *bindto) +{ struct rad_server *srvp; + struct addrinfo hints, *res, *res0; + char servname[NI_MAXSERV]; + int error; if (h->num_servers >= MAXSERVERS) { generr(h, "Too many RADIUS servers specified"); return -1; } - srvp = &h->servers[h->num_servers]; - memset(&srvp->addr, 0, sizeof srvp->addr); - srvp->addr.sin_len = sizeof srvp->addr; - srvp->addr.sin_family = AF_INET; - if (!inet_aton(host, &srvp->addr.sin_addr)) { - struct hostent *hent; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_ADDRCONFIG; + if (bindto == NULL) { +#if defined(INET) && defined(INET6) + hints.ai_family = PF_UNSPEC; +#elif defined(INET) + hints.ai_family = PF_INET; +#elif defined(INET6) + hints.ai_family = PF_INET6; +#endif + } else { + hints.ai_family = bindto->sa_family; + } + hints.ai_socktype = SOCK_DGRAM; + if (port != 0) { + snprintf(servname, sizeof(servname), "%d", port); + } else if (h->type == RADIUS_AUTH) { + snprintf(servname, sizeof(servname), "radius"); + } else { + snprintf(servname, sizeof(servname), "radacct"); + } + error = getaddrinfo(host, servname, &hints, &res0); + if (error != 0) { + if (strchr(host, ':') != NULL) { + generr(h, "[%s]:%d: %s", host, port, + gai_strerror(error)); + } else { + generr(h, "%s:%d: %s", host, port, gai_strerror(error)); + } + return -1; + } - if ((hent = gethostbyname(host)) == NULL) { - generr(h, "%s: host not found", host); + error = ENOENT; + srvp = &h->servers[h->num_servers]; + for (res = res0; res != NULL; res = res->ai_next) { + if ((srvp->secret = strdup(secret)) == NULL) { + generr(h, "Out of memory"); return -1; } - memcpy(&srvp->addr.sin_addr, hent->h_addr, - sizeof srvp->addr.sin_addr); + + memcpy(&srvp->addr, res->ai_addr, res->ai_addrlen); + srvp->timeout = timeout; + srvp->max_tries = tries; + srvp->num_tries = 0; + srvp->is_dead = 0; + srvp->dead_time = dead_time; + srvp->next_probe = 0; + server_bindto(srvp, res->ai_family, bindto); + if (h->num_servers == 0) { + h->srv = 0; + memcpy(&h->bindto, &srvp->bindto, sizeof(h->bindto)); + } + h->num_servers++; + + error = 0; + + if (h->num_servers >= MAXSERVERS) { + break; + } + srvp = &h->servers[h->num_servers]; } - if (port != 0) - srvp->addr.sin_port = htons((u_short)port); - else { - struct servent *sent; - if (h->type == RADIUS_AUTH) - srvp->addr.sin_port = - (sent = getservbyname("radius", "udp")) != NULL ? - sent->s_port : htons(RADIUS_PORT); - else - srvp->addr.sin_port = - (sent = getservbyname("radacct", "udp")) != NULL ? - sent->s_port : htons(RADACCT_PORT); - } - if ((srvp->secret = strdup(secret)) == NULL) { - generr(h, "Out of memory"); + freeaddrinfo(res0); + + if (error != 0) { + generr(h, "No address found"); return -1; } - srvp->timeout = timeout; - srvp->max_tries = tries; - srvp->num_tries = 0; - srvp->is_dead = 0; - srvp->dead_time = dead_time; - srvp->next_probe = 0; - srvp->bindto = bindto->s_addr; - h->num_servers++; + return 0; } @@ -461,13 +562,151 @@ free(h); } +#ifdef INET void rad_bind_to(struct rad_handle *h, in_addr_t addr) { + struct sockaddr_in sin; - h->bindto = addr; + memset(&sin, 0, sizeof sin); + sin.sin_len = sizeof sin; + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = addr; + rad_set_bindto(h, (struct sockaddr *)&sin); } +#endif +void +rad_set_bindto(struct rad_handle *h, const struct sockaddr *addr) +{ + + memset(&h->bindto, 0, sizeof(h->bindto)); + memcpy(&h->bindto, addr, addr->sa_len); +} + +static struct sockaddr * +string_to_sockaddr(const char *str, struct sockaddr_storage *ss) +{ + union { +#ifdef INET + struct in_addr addr4; +#endif +#ifdef INET6 + struct in6_addr addr6; +#endif + } addr; + int ret; + +#ifdef INET + ret = inet_pton(AF_INET, str, &addr); + if (ret == -1) { + return NULL; + } else if (ret == 1) { + struct sockaddr_in *sin; + + memset(ss, 0, sizeof(*ss)); + sin = (struct sockaddr_in *)ss; + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_port = 0; + memcpy(&sin->sin_addr, &addr, sizeof(sin->sin_addr)); + return (struct sockaddr *)ss; + } + assert(ret == 0); +#endif + +#ifdef INET6 + ret = inet_pton(AF_INET6, str, &addr); + if (ret == -1) { + return NULL; + } else if (ret == 1) { + struct sockaddr_in6 *sin6; + + memset(ss, 0, sizeof(*ss)); + sin6 = (struct sockaddr_in6 *)ss; + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + memcpy(&sin6->sin6_addr, &addr, sizeof(sin6->sin6_addr)); + return (struct sockaddr *)ss; + } + assert(ret == 0); +#endif + + errno = EINVAL; + return NULL; +} + +static char * +extract_host_and_port(struct rad_handle *h, const char *path, int linenum, + char *addr, int *portp) +{ + char *end, *pp; + + /* + * There are following cases to consider: + * - hostname without a port, eg. freefall.freebsd.org + * - hostname with a port, eg. freefall.freebsd.org:1812 + * - IPv4 address without a port, eg. 192.168.0.1 + * - IPv4 address with a port, eg. 192.168.0.1:1812 + * - IPv6 address without a port, eg. fe80::1 + * - IPv6 address without a port, eg. [fe80::1] + * - IPv6 address with a port, eg. [fe80::1]:1812 + */ + if (strchr(addr, ':') != strrchr(addr, ':')) { + /* IPv6 */ + if (addr[0] == '[') { + addr++; + pp = strrchr(addr, ']'); + if (pp != NULL) { + *pp = '\0'; + pp++; + if (*pp == '\0') { + pp = NULL; + } else if (*pp == ':') { + pp++; + } else { + generr(h, "%s:%d: invalid address", + path, linenum); + return (NULL); + } + + } else { + generr(h, "%s:%d: invalid address", path, + linenum); + return (NULL); + } + } else { + pp = NULL; + } + } else { + /* IPv4 or hostname. */ + pp = strrchr(addr, ':'); + if (pp != NULL) { + *pp = '\0'; + pp++; + } + } + if (pp == NULL) { + *portp = 0; + } else { + int keep_errno; + + keep_errno = errno; + errno = 0; + *portp = strtoul(pp, &end, 10); + if (errno != 0 || *end != '\0') { + generr(h, "%s:%d: invalid port", path, linenum); + errno = keep_errno; + return (NULL); + } + errno = keep_errno; + } + + return (addr); +} + int rad_config(struct rad_handle *h, const char *path) { @@ -490,8 +729,7 @@ int nfields; char msg[ERRSIZE]; char *type; - char *host, *res; - char *port_str; + char *host; char *secret; char *timeout_str; char *maxtries_str; @@ -503,7 +741,8 @@ unsigned long maxtries; unsigned long dead_time; int port; - struct in_addr bindto; + struct sockaddr_storage bindss; + struct sockaddr *bindto; int i; linenum++; @@ -569,19 +808,11 @@ continue; /* Parse and validate the fields. */ - res = host; - host = strsep(&res, ":"); - port_str = strsep(&res, ":"); - if (port_str != NULL) { - port = strtoul(port_str, &end, 10); - if (*end != '\0') { - generr(h, "%s:%d: invalid port", path, - linenum); - retval = -1; - break; - } - } else - port = 0; + host = extract_host_and_port(h, path, linenum, host, &port); + if (host == NULL) { + retval = -1; + break; + } if (timeout_str != NULL) { timeout = strtoul(timeout_str, &end, 10); if (*end != '\0') { @@ -615,20 +846,19 @@ dead_time = DEAD_TIME; if (bindto_str != NULL) { - bindto.s_addr = inet_addr(bindto_str); - if (bindto.s_addr == INADDR_NONE) { + bindto = string_to_sockaddr(bindto_str, &bindss); + if (bindto == NULL) { generr(h, "%s:%d: invalid bindto", path, linenum); retval = -1; break; } } else - bindto.s_addr = INADDR_ANY; + bindto = NULL; - if (rad_add_server_ex(h, host, port, secret, timeout, maxtries, - dead_time, &bindto) == -1) { - strcpy(msg, h->errmsg); - generr(h, "%s:%d: %s", path, linenum, msg); + if (rad_add_server_bindto(h, host, port, secret, timeout, + maxtries, dead_time, bindto) == -1) { + generr(h, "%s:%d: %s", path, linenum, h->errmsg); retval = -1; break; } @@ -653,14 +883,13 @@ { int n, cur_srv; time_t now; - struct sockaddr_in sin; if (h->type == RADIUS_SERVER) { generr(h, "denied function call"); - return (-1); + return -1; } if (selected) { - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; fromlen = sizeof from; @@ -670,7 +899,8 @@ generr(h, "recvfrom: %s", strerror(errno)); return -1; } - if (is_valid_response(h, h->srv, &from)) { + if (is_valid_response(h, h->srv, + (const struct sockaddr *)&from)) { h->in_len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1]; h->in_pos = POS_ATTRS; @@ -708,29 +938,27 @@ if (h->srv == cur_srv) { generr(h, "No valid RADIUS responses received"); - return (-1); + return -1; } } /* Rebind */ - if (h->bindto != h->servers[h->srv].bindto) { - h->bindto = h->servers[h->srv].bindto; + if (memcmp(&h->bindto, &h->servers[h->srv].bindto, + sizeof(h->bindto)) != 0) { + memcpy(&h->bindto, &h->servers[h->srv].bindto, + sizeof(h->bindto)); close(h->fd); - if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + if ((h->fd = socket(h->bindto.ss_family, SOCK_DGRAM, + IPPROTO_UDP)) == -1) { generr(h, "Cannot create socket: %s", strerror(errno)); return -1; } - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof sin; - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = h->bindto; - sin.sin_port = 0; - if (bind(h->fd, (const struct sockaddr *)&sin, - sizeof sin) == -1) { + if (bind(h->fd, (const struct sockaddr *)&h->bindto, + h->bindto.ss_len) == -1) { generr(h, "bind: %s", strerror(errno)); close(h->fd); h->fd = -1; - return (-1); + return -1; } } @@ -750,7 +978,7 @@ /* Send the request */ n = sendto(h->fd, h->out, h->out_len, 0, (const struct sockaddr *)&h->servers[h->srv].addr, - sizeof h->servers[h->srv].addr); + h->servers[h->srv].addr.ss_len); if (n != h->out_len) tv->tv_sec = 1; /* Do not wait full timeout if send failed. */ else @@ -765,7 +993,7 @@ int rad_receive_request(struct rad_handle *h) { - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; int n; @@ -782,8 +1010,8 @@ return (-1); } for (n = 0; n < h->num_servers; n++) { - if (h->servers[n].addr.sin_addr.s_addr == from.sin_addr.s_addr) { - h->servers[n].addr.sin_port = from.sin_port; + if (memcmp(&h->servers[n].addr, &from, + h->servers[n].addr.ss_len) == 0) { h->srv = n; break; } @@ -791,8 +1019,7 @@ if (h->srv == -1) return (-2); if (is_valid_request(h)) { - h->in_len = h->in[POS_LENGTH] << 8 | - h->in[POS_LENGTH+1]; + h->in_len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1]; h->in_pos = POS_ATTRS; return (h->in[POS_CODE]); } @@ -806,7 +1033,7 @@ if (h->type != RADIUS_SERVER) { generr(h, "denied function call"); - return (-1); + return -1; } /* Fill in the length field in the message */ h->out[POS_LENGTH] = h->out_len >> 8; @@ -819,7 +1046,7 @@ /* Send the request */ n = sendto(h->fd, h->out, h->out_len, 0, (const struct sockaddr *)&h->servers[h->srv].addr, - sizeof h->servers[h->srv].addr); + h->servers[h->srv].addr.ss_len); if (n != h->out_len) { if (n == -1) generr(h, "sendto: %s", strerror(errno)); @@ -838,11 +1065,11 @@ if (h->type == RADIUS_SERVER) { generr(h, "denied function call"); - return (-1); + return -1; } if (h->num_servers == 0) { generr(h, "No RADIUS servers specified"); - return (-1); + return -1; } h->out[POS_CODE] = code; h->out[POS_IDENT] = ++h->ident; @@ -869,7 +1096,7 @@ if (h->type != RADIUS_SERVER) { generr(h, "denied function call"); - return (-1); + return -1; } h->out[POS_CODE] = code; h->out[POS_IDENT] = h->in[POS_IDENT]; @@ -881,6 +1108,7 @@ return 0; } +#ifdef INET struct in_addr rad_cvt_addr(const void *data) { @@ -889,7 +1117,9 @@ memcpy(&value.s_addr, data, sizeof value.s_addr); return value; } +#endif +#ifdef INET6 struct in6_addr rad_cvt_addr6(const void *data) { @@ -898,6 +1128,7 @@ memcpy(&value.s6_addr, data, sizeof value.s6_addr); return value; } +#endif u_int32_t rad_cvt_int(const void *data) @@ -955,25 +1186,20 @@ { int srv; time_t now; - struct sockaddr_in sin; if (h->type == RADIUS_SERVER) { generr(h, "denied function call"); - return (-1); + return -1; } /* Make sure we have a socket to use */ if (h->fd == -1) { - if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + if ((h->fd = socket(h->bindto.ss_family, SOCK_DGRAM, + IPPROTO_UDP)) == -1) { generr(h, "Cannot create socket: %s", strerror(errno)); return -1; } - memset(&sin, 0, sizeof sin); - sin.sin_len = sizeof sin; - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = h->bindto; - sin.sin_port = htons(0); - if (bind(h->fd, (const struct sockaddr *)&sin, - sizeof sin) == -1) { + if (bind(h->fd, (const struct sockaddr *)&h->bindto, + h->bindto.ss_len) == -1) { generr(h, "bind: %s", strerror(errno)); close(h->fd); h->fd = -1; @@ -1061,7 +1287,7 @@ h->type = RADIUS_AUTH; h->out_created = 0; h->eap_msg = 0; - h->bindto = INADDR_ANY; + memset(&h->bindto, 0, sizeof(h->bindto)); } return h; } @@ -1096,18 +1322,22 @@ return rad_auth_open(); } +#ifdef INET int rad_put_addr(struct rad_handle *h, int type, struct in_addr addr) { return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr); } +#endif +#ifdef INET6 int rad_put_addr6(struct rad_handle *h, int type, struct in6_addr addr) { return rad_put_attr(h, type, &addr.s6_addr, sizeof addr.s6_addr); } +#endif int rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len) @@ -1343,6 +1573,7 @@ return (attr->attrib_type); } +#ifdef INET int rad_put_vendor_addr(struct rad_handle *h, int vendor, int type, struct in_addr addr) @@ -1350,7 +1581,9 @@ return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr, sizeof addr.s_addr)); } +#endif +#ifdef INET6 int rad_put_vendor_addr6(struct rad_handle *h, int vendor, int type, struct in6_addr addr) @@ -1359,6 +1592,7 @@ return (rad_put_vendor_attr(h, vendor, type, &addr.s6_addr, sizeof addr.s6_addr)); } +#endif int rad_put_vendor_attr(struct rad_handle *h, int vendor, int type, Index: radlib_private.h =================================================================== --- radlib_private.h +++ radlib_private.h @@ -66,7 +66,7 @@ #define POS_ATTRS 20 /* Start of attributes */ struct rad_server { - struct sockaddr_in addr; /* Address of server */ + struct sockaddr_storage addr; /* Address of server */ char *secret; /* Shared secret */ int timeout; /* Timeout in seconds */ int max_tries; /* Number of tries before giving up */ @@ -74,7 +74,7 @@ int is_dead; /* The server did not answer last time */ time_t dead_time; /* Don't try this server for the time period if it is dead */ time_t next_probe; /* Time of a next probe after failure */ - in_addr_t bindto; /* Bind to address */ + struct sockaddr_storage bindto; /* Bind to address */ }; struct rad_handle { @@ -97,7 +97,7 @@ int in_pos; /* Current position scanning attrs */ int srv; /* Server number we did last */ int type; /* Handle type */ - in_addr_t bindto; /* Current bind address */ + struct sockaddr_storage bindto; /* Current bind address */ }; struct vendor_attribute {