Page MenuHomeFreeBSD

libradius(3) IPv6 support
Needs ReviewPublic

Authored by pjd on Jul 9 2018, 11:49 PM.



Implement IPv6 support in libradius.

As a bonus if a hostname is given to rad_add_server_bindto() function and this hostname resolves to multiple IP addresses we will create a rad_server for each IP address.

Diff Detail

Lint Skipped
Unit Tests Skipped

Event Timeline

pjd created this revision.Jul 9 2018, 11:49 PM
bz added a comment.Jul 10 2018, 12:15 AM

This feels like a 15 year old patch I've seen before.

Also can we add #ifdefs for INET and INET6 for WITH_INET_SUPPORT and WITH_INET6_SUPPORT?

bz added a reviewer: hrs.Jul 10 2018, 12:19 AM
pjd added a comment.Jul 10 2018, 12:30 AM

You are probably talking about this one:
I've tried it, but it is very out-dated and has some bugs. It also keeps server on a TAILQ, which is nice, but I don't think it should be combined. The nice thing about that patch was to add multiple servers when a hostname resolves to multiple IP addresses, which I also implemented.

pjd updated this revision to Diff 45092.Jul 10 2018, 1:39 AM
  • Allow for optional compilation without IPv4 or IPv6 support.
  • Make it possible to use IPv6 addresses in configuration file.
  • Call getaddrinfo(3) with flags set to AI_ADDRCONFIG.
oshogbo requested changes to this revision.Jul 10 2018, 10:22 AM
oshogbo added inline comments.


sa = NULL;

if (bindto != NULL) {


I just wonder if we should add some somewhere check that at least one INET or INET6 was given?


Extra space.
Maybe assert the snprintf output?


Shouldn't we gen some warning about that?
Like above.


Maybe simplify that:

if (pp == NULL) {

[rest of code without else]

Maybe we want to check here also the range of port?
We shouldnt also errno check only if *portp is equals to 0 ?


I don't thing we should retake the errno here.


Style: POS_LENGTH + 1

This revision now requires changes to proceed.Jul 10 2018, 10:22 AM
oshogbo added inline comments.Jul 10 2018, 10:30 AM

*We should check errno only if *portp is equals to 0.

pjd marked 5 inline comments as done.Jul 10 2018, 3:09 PM
pjd added inline comments.

I prefer the way it is now, so sa is not set twice.


Space fixed. assert() seems excessive.


No. This is not an error if host resolves to too many IPs. It is enough if we add one new server. The rest will be added if there is room.


Good idea.


errno shouldn't change if the function succeeds.


Correct, thanks.


I don't want to change this style yet. I'll actually revert merging those two lines for now.

pjd updated this revision to Diff 45115.Jul 10 2018, 3:11 PM
pjd marked 3 inline comments as done.

Revert style changes.
Remove #ifdef INET checks from radlib.h, it prevents some consumers from compiling.
Implement some of oshogbo suggestions.

hrs added inline comments.Jul 11 2018, 11:00 AM

A comparison of sa_family is redundant if applying memcmp() to whole of the struct sockaddr_storage.


You can obtain a struct sockaddr for INADDR_ANY by getaddrinfo(NULL, "radacct", &(struct addrinfo){.ai_flags = AI_PASSIVE}, &res) for both INET and INET6 depending on .ai_family. It is guaranteed that a single struct addrinfo will return when an AF is specified in .ai_family.

As described below, I think "bindto" variable can be struct addrinfo instead of struct sockaddr to make the code simpler.


Is there any reason to keep "port" as int? If this API is brand-new and there is no calculation by using the port number, const char *port is easier to handle. After all, "int port" has to be converted into (char *) for getaddrinfo(3) and then getaddrinfo(3) converts back it to uint16_t for (struct sockaddr)->sin{,6}_port.


This function can be simply replaced with getaddrinfo(3). getaddrinfo(str, "0", &(struct addrinfo){.ai_flags = AI_NUMERICSERV}, &res) should do the same job in a transport-independent fashion.

getaddrinfo(3) is the universal tool to get a struct sockaddr from address information. However, I recommend to directly use struct addrinfo for "bindto" because it includes all of the information required for both bind(2) and socket(2). There is no need to take care of struct sockaddr_storage directly in that case though freeaddrinfo(3) is required to free the allocated memory space at some point.


I have no strong opinion and this is just a comment, but I personally think that conversion of the port number to int and validation of the port range are redundant. If this is required, a call of getaddrinfo (here again) is sufficient. Checking if pp points a string and it is a valid port number can be done by getaddrinfo(NULL, pp, &(struct addrinfo){.ai_flags = AI_NUMERICSERV}, &res) == 0. It is quite light and does not involve either any lookup of DNS or /etc/services. Whether the port number is 0 or not can be tested by converting ai_addr by getnameinfo() with NI_NUMERICSERV and comparing the result with "0" since it canonicalizes the expression. While these may be a overkill, putting similar validation checks by using a magic number such as 65535 in many places is something we should avoid.

pjd added inline comments.Jul 13 2018, 2:02 PM

What would be your opinion about changing bindto to 'const char *'? This would be consistent with 'host' and I think in majority of cases the consumer would have string anyway. I'd still like to keep port as 'int' or even 'unsigned it', this for me sounds like a more common type for port.


Ip refer int, or even unsigned int for port, because this is how I expect consumer of this API will have the port. This is how we keep port in our product. On the other hand, I'm thinking about changing bindto to string and would love to hear your thoughts on this.