All of lore.kernel.org
 help / color / mirror / Atom feed
* patch getaddrinfo.3 with "protocol independent" information
@ 2016-02-26  3:01 Bill Kerr
       [not found] ` <56CFC01F.60702-7Y6McbBI5zQ@public.gmane.org>
  0 siblings, 1 reply; 3+ messages in thread
From: Bill Kerr @ 2016-02-26  3:01 UTC (permalink / raw)
  To: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w, Jerry Cooperstein,
	linux-man-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2518 bytes --]

Michael,

I'm one of the instructors for the Linux Foundation.  Jerry Cooperstein 
posted a note to the instructor's mailing list that he's going to update 
the network programming chapters of LFD312.  A couple of us suggested 
that he retire the exercises that use the obsolete library calls 
gethostbyname(3) and friends, replacing with with code using getaddrinfo(3).

I noted that a lot of example code out there, including (sigh) early 
editions of the Richard Stevens book "UNIX  Network Programming, Vol. 1" 
fail to accomplish what Stevens says is a goal of network programming:  
"protocol independence."

A "protocol independent" server exposes the server's socket at ALL of 
the server's IP addresses:  IPv4 and IPv6, local and remote.

The current getaddrinfo(3) man page gets PART of the way to instructing 
how to do this.

The missing part is that after setting the "hints" struct to ai_family = 
AF_UNSPEC and ai_flags = AI_PASSIVE, the code needs to CHECK the 
"ai_family" of each candidate address in the list returned by 
getaddrinfo(3) to preferentially choose AF_INET6 over AF_INET.

If the server (preferentially) binds to an IPv6 address, qualified as 
"AF_UNSPEC" and "AI_PASSIVE" in the hints, then the resulting socket 
will be visible at ANY and ALL of the server's IP addresses. If the 
server binds to an IPv4 address candidate (because the address 
candidates in the list aren't checked before trying to bind), then the 
socket is unavailable to clients trying any of the server's IPv6 
addresses.  This is arguably an inferior result.

I attach a patch file against the top of  the man-pages tree (version 
4.05) with modifications to two parts of man3/getaddrinfo.3:

   -> the section describing AF_UNSPEC is expanded with a "programming 
note" describing how to write a "protocol independent" server.

   -> the "server" example code has about 6 lines of code added, PLUS an 
expansion of the block comment before the loop that walks the list 
returned by getaddrinfo(3).

Thanks for considering this patch.  Please let me know what I've done 
horribly wrong, and I'll try to fix it.  I think this is somewhat 
important, as writing "protocol independent" servers is fairly 
important, and MOST of the code examples out on the Web and elsewhere 
don't CHECK the address candidates when walking the list returned by 
getaddrinfo(3).   That's all that needs to be done to make network 
servers better.

  == Bill Kerr
         bilker-7Y6McbBI5zQ@public.gmane.org
         503 781-7946


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: getaddrinfo.patch --]
[-- Type: text/x-patch; name="getaddrinfo.patch", Size: 3208 bytes --]

diff -Naur man-pages-orig/man3/getaddrinfo.3 man-pages/man3/getaddrinfo.3
--- man-pages-orig/man3/getaddrinfo.3	2016-02-25 16:12:10.918563230 -0800
+++ man-pages/man3/getaddrinfo.3	2016-02-25 08:52:27.049057533 -0800
@@ -154,7 +154,20 @@
 (either IPv4 or IPv6, for example) that can be used with
 .I node
 and
-.IR service .
+.IR service .  
+.I Programming Note:  
+in order to create a server socket that can be reached at
+.I both
+the server's IPv4 and IPv6 addresses, you should
+.I preferentially
+bind with AF_INET6 addresses returned by
+.BR getaddrinfo () ,
+as binding with an AF_INET address will create a socket incapable
+of accepting connections on the server's IPv6 addresses.  In other words,
+as you walk the list of candidate addresses, you should prefer
+binding with those whose
+.I ai_family
+is AF_INET6, rather than AF_INET.
 .TP
 .I ai_socktype
 This field specifies the preferred socket type, for example
@@ -675,6 +688,7 @@
     socklen_t peer_addr_len;
     ssize_t nread;
     char buf[BUF_SIZE];
+    int loops;
 
     if (argc != 2) {
         fprintf(stderr, "Usage: %s port\\n", argv[0]);
@@ -697,22 +711,39 @@
     }
 
     /* getaddrinfo() returns a list of address structures.
-       Try each address until we successfully bind(2).
-       If socket(2) (or bind(2)) fails, we (close the socket
-       and) try the next address. */
-
-    for (rp = result; rp != NULL; rp = rp\->ai_next) {
-        sfd = socket(rp\->ai_family, rp\->ai_socktype,
-                rp\->ai_protocol);
-        if (sfd == \-1)
-            continue;
+       Pass through the list UP TO twice.  On the first pass,
+       SKIP addresses that are NOT AF_INET6.  If socket(2) and
+       bind(2) both succeed on a candidate, we are done.  Else,
+       close the socket and try the next address.  If we didn't
+       find an IPv6 address on the first pass, try a second pass,
+       this time try ALL candidates in the list.  If we get an
+       IPv6 address, the "hints" AF_UNSPEC and AI_PASSIVE will
+       ensure that the socket can be reached by all client programs
+       trying ANY of our IP addresses:  v4 or v6, local or remote.
+       This is an useful and important property of network
+       programming called "protocol independence."  See Richard
+       Stevens, "UNIX  Network Programming, Vol. 1". */
+       
+    for (loops = 0; loops < 2; loops++) {
+        for (rp = result; rp != NULL; rp = rp\->ai_next) {
+
+            /* SKIP all but IPv6 candidates on 1st pass */
+            if (loops == 0 && rp\->ai_family != AF_INET6)
+                    continue;
+
+            sfd = socket(rp\->ai_family, rp\->ai_socktype,
+                    rp\->ai_protocol);
+            if (sfd == \-1)
+                continue;
 
-        if (bind(sfd, rp\->ai_addr, rp\->ai_addrlen) == 0)
-            break;                  /* Success */
+            if (bind(sfd, rp\->ai_addr, rp\->ai_addrlen) == 0)
+                goto out;                  /* Success */
 
-        close(sfd);
+            close(sfd);
+        }
     }
 
+out:
     if (rp == NULL) {               /* No address succeeded */
         fprintf(stderr, "Could not bind\\n");
         exit(EXIT_FAILURE);

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: patch getaddrinfo.3 with "protocol independent" information
       [not found] ` <56CFC01F.60702-7Y6McbBI5zQ@public.gmane.org>
@ 2016-02-26 19:51   ` Michael Kerrisk (man-pages)
       [not found]     ` <CAKgNAkj_QsPTqUdoKgmZpEuotSoQuzykZyoDyKxaL4r7eNeZ0A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Kerrisk (man-pages) @ 2016-02-26 19:51 UTC (permalink / raw)
  To: bilker-7Y6McbBI5zQ; +Cc: Jerry Cooperstein, linux-man

Hi Bill,

On 26 February 2016 at 04:01, Bill Kerr <bilker-7Y6McbBI5zQ@public.gmane.org> wrote:
> Michael,
>
> I'm one of the instructors for the Linux Foundation.  Jerry Cooperstein
> posted a note to the instructor's mailing list that he's going to update the
> network programming chapters of LFD312.  A couple of us suggested that he
> retire the exercises that use the obsolete library calls gethostbyname(3)
> and friends, replacing with with code using getaddrinfo(3).
>
> I noted that a lot of example code out there, including (sigh) early
> editions of the Richard Stevens book "UNIX  Network Programming, Vol. 1"

But later editions of UNP also do not seem to do this in the code...

> fail to accomplish what Stevens says is a goal of network programming:
> "protocol independence."
>
> A "protocol independent" server exposes the server's socket at ALL of the
> server's IP addresses:  IPv4 and IPv6, local and remote.
>
> The current getaddrinfo(3) man page gets PART of the way to instructing how
> to do this.
>
> The missing part is that after setting the "hints" struct to ai_family =
> AF_UNSPEC and ai_flags = AI_PASSIVE, the code needs to CHECK the "ai_family"
> of each candidate address in the list returned by getaddrinfo(3) to
> preferentially choose AF_INET6 over AF_INET.
>
> If the server (preferentially) binds to an IPv6 address, qualified as
> "AF_UNSPEC" and "AI_PASSIVE" in the hints, then the resulting socket will be
> visible at ANY and ALL of the server's IP addresses. If the server binds to
> an IPv4 address candidate (because the address candidates in the list aren't
> checked before trying to bind), then the socket is unavailable to clients
> trying any of the server's IPv6 addresses.  This is arguably an inferior
> result.

Okay -- I see the point, I think; but see below.

> I attach a patch file against the top of  the man-pages tree (version 4.05)
> with modifications to two parts of man3/getaddrinfo.3:
>
>   -> the section describing AF_UNSPEC is expanded with a "programming note"
> describing how to write a "protocol independent" server.
>
>   -> the "server" example code has about 6 lines of code added, PLUS an
> expansion of the block comment before the loop that walks the list returned
> by getaddrinfo(3).
>
> Thanks for considering this patch.  Please let me know what I've done
> horribly wrong, and I'll try to fix it.  I think this is somewhat important,
> as writing "protocol independent" servers is fairly important, and MOST of
> the code examples out on the Web and elsewhere don't CHECK the address
> candidates when walking the list returned by getaddrinfo(3).   That's all
> that needs to be done to make network servers better.
>
>  == Bill Kerr
>         bilker-7Y6McbBI5zQ@public.gmane.org
>         503 781-7946

Thanks for raising this. But I am a bit doubtful. I've not seen this
advice anywhere else, and I've not at a quick (far from exhaustive)
search found any code that does this. Can you point me at some real
project/production code that does this? My main thought here is: isn't
this what /etc/gai.conf
(http://man7.org/linux/man-pages/man5/gai.conf.5.html) is about? That
is, the choice of preferred protocol is something that should be
configured at system level, rather than application level, and in
cases where it matters, /etc/gai.conf should be defined so that IPv6
addresses are returned first.

Thanks,

Michael


-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: patch getaddrinfo.3 with "protocol independent" information
       [not found]     ` <CAKgNAkj_QsPTqUdoKgmZpEuotSoQuzykZyoDyKxaL4r7eNeZ0A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2016-03-02  8:00       ` Michael Kerrisk (man-pages)
  0 siblings, 0 replies; 3+ messages in thread
From: Michael Kerrisk (man-pages) @ 2016-03-02  8:00 UTC (permalink / raw)
  To: Bill Kerr; +Cc: Jerry Cooperstein, linux-man

Hi Pill,

Ping + one or two clarifications below...

On 26 February 2016 at 20:51, Michael Kerrisk (man-pages)
<mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Hi Bill,
>
> On 26 February 2016 at 04:01, Bill Kerr <bilker-7Y6McbBI5zQ@public.gmane.org> wrote:
>> Michael,
>>
>> I'm one of the instructors for the Linux Foundation.  Jerry Cooperstein
>> posted a note to the instructor's mailing list that he's going to update the
>> network programming chapters of LFD312.  A couple of us suggested that he
>> retire the exercises that use the obsolete library calls gethostbyname(3)
>> and friends, replacing with with code using getaddrinfo(3).
>>
>> I noted that a lot of example code out there, including (sigh) early
>> editions of the Richard Stevens book "UNIX  Network Programming, Vol. 1"
>
> But later editions of UNP also do not seem to do this in the code...

What I meant here was: it looks like the code from later editions of
UNPv1 also does not employ the technique you suggest below.

>> fail to accomplish what Stevens says is a goal of network programming:
>> "protocol independence."
>>
>> A "protocol independent" server exposes the server's socket at ALL of the
>> server's IP addresses:  IPv4 and IPv6, local and remote.
>>
>> The current getaddrinfo(3) man page gets PART of the way to instructing how
>> to do this.
>>
>> The missing part is that after setting the "hints" struct to ai_family =
>> AF_UNSPEC and ai_flags = AI_PASSIVE, the code needs to CHECK the "ai_family"
>> of each candidate address in the list returned by getaddrinfo(3) to
>> preferentially choose AF_INET6 over AF_INET.
>>
>> If the server (preferentially) binds to an IPv6 address, qualified as
>> "AF_UNSPEC" and "AI_PASSIVE" in the hints, then the resulting socket will be
>> visible at ANY and ALL of the server's IP addresses. If the server binds to
>> an IPv4 address candidate (because the address candidates in the list aren't
>> checked before trying to bind), then the socket is unavailable to clients
>> trying any of the server's IPv6 addresses.  This is arguably an inferior
>> result.
>
> Okay -- I see the point, I think; but see below.
>
>> I attach a patch file against the top of  the man-pages tree (version 4.05)
>> with modifications to two parts of man3/getaddrinfo.3:
>>
>>   -> the section describing AF_UNSPEC is expanded with a "programming note"
>> describing how to write a "protocol independent" server.
>>
>>   -> the "server" example code has about 6 lines of code added, PLUS an
>> expansion of the block comment before the loop that walks the list returned
>> by getaddrinfo(3).
>>
>> Thanks for considering this patch.  Please let me know what I've done
>> horribly wrong, and I'll try to fix it.  I think this is somewhat important,
>> as writing "protocol independent" servers is fairly important, and MOST of
>> the code examples out on the Web and elsewhere don't CHECK the address
>> candidates when walking the list returned by getaddrinfo(3).   That's all
>> that needs to be done to make network servers better.
>>
>>  == Bill Kerr
>>         bilker-7Y6McbBI5zQ@public.gmane.org
>>         503 781-7946
>
> Thanks for raising this. But I am a bit doubtful. I've not seen this
> advice anywhere else, and I've not at a quick (far from exhaustive)
> search found any code that does this. Can you point me at some real
> project/production code that does this?

I grepped a little more through various source code, but have still
yet to find some projects that follow the approach described above.
So, I'd be interested in pointers to such code.

> My main thought here is: isn't
> this what /etc/gai.conf
> (http://man7.org/linux/man-pages/man5/gai.conf.5.html) is about? That
> is, the choice of preferred protocol is something that should be
> configured at system level, rather than application level, and in
> cases where it matters, /etc/gai.conf should be defined so that IPv6
> addresses are returned first.

Cheers,

Michael

-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-03-02  8:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-26  3:01 patch getaddrinfo.3 with "protocol independent" information Bill Kerr
     [not found] ` <56CFC01F.60702-7Y6McbBI5zQ@public.gmane.org>
2016-02-26 19:51   ` Michael Kerrisk (man-pages)
     [not found]     ` <CAKgNAkj_QsPTqUdoKgmZpEuotSoQuzykZyoDyKxaL4r7eNeZ0A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-03-02  8:00       ` Michael Kerrisk (man-pages)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.