xref: /freebsd/crypto/krb5/src/lib/krb5/os/t_gifconf.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* SIOCGIFCONF:
3 
4    The behavior of this ioctl varies across systems.
5 
6    The "largest gap" values are the largest number of bytes I've seen
7    left unused at the end of the supplied buffer when there were more
8    entries to return.  These values may of coures be dependent on the
9    configurations of the particular systems I was testing with.
10 
11    NetBSD 1.5-alpha: The returned ifc_len is the desired amount of
12    space, always.  The returned list may be truncated if there isn't
13    enough room; no overrun.  Largest gap: 43.  (NetBSD now has
14    getifaddrs.)
15 
16    BSD/OS 4.0.1 (courtesy djm): The returned ifc_len is equal to or
17    less than the supplied ifc_len.  Sometimes the entire buffer is
18    used; sometimes N-1 bytes; occasionally, the buffer must have quite
19    a bit of extra room before the next structure will be added.
20    Largest gap: 39.
21 
22    Solaris 7,8: Return EINVAL if the buffer space is too small for all
23    the data to be returned, including ifc_len==0.  Solaris is the only
24    system I've found so far that actually returns an error.  No gap.
25    However, SIOCGIFNUM may be used to query the number of interfaces.
26 
27    Linux 2.2.12 (RH 6.1 dist, x86): The buffer is filled in with as
28    many entries as will fit, and the size used is returned in ifc_len.
29    The list is truncated if needed, with no indication.  Largest gap: 31.
30 
31    IRIX 6.5: The buffer is filled in with as many entries as will fit
32    in N-1 bytes, and the size used is returned in ifc_len.  Providing
33    exactly the desired number of bytes is inadequate; the buffer must
34    be *bigger* than needed.  (E.g., 32->0, 33->32.)  The returned
35    ifc_len is always less than the supplied one.  Largest gap: 32.
36 
37    AIX 4.3.3: Sometimes the returned ifc_len is bigger than the
38    supplied one, but it may not be big enough for *all* the
39    interfaces.  Sometimes it's smaller than the supplied value, even
40    if the returned list is truncated.  The list is filled in with as
41    many entries as will fit; no overrun.  Largest gap: 143.
42 
43    Older AIX: We're told by W. David Shambroom <DShambroom@gte.com> in
44    PR krb5-kdc/919 that older versions of AIX have a bug in the
45    SIOCGIFCONF ioctl which can cause them to overrun the supplied
46    buffer.  However, we don't yet have details as to which version,
47    whether the overrun amount was bounded (e.g., one ifreq's worth) or
48    not, whether it's a real buffer overrun or someone assuming it was
49    because ifc_len was increased, etc.  Once we've got details, we can
50    try to work around the problem.
51 
52    Digital UNIX 4.0F: If input ifc_len is zero, return an ifc_len
53    that's big enough to include all entries.  (Actually, on our
54    system, it appears to be larger than that by 32.)  If input ifc_len
55    is nonzero, fill in as many entries as will fit, and set ifc_len
56    accordingly.  (Tested only with INIT of zero.)
57 
58    So... if the returned ifc_len is bigger than the supplied one,
59    we'll need at least that much space -- but possibly more -- to hold
60    all the results.  If the returned value is smaller or the same, we
61    may still need more space.
62 
63    Using this ioctl is going to be messy.  Let's just hope that
64    getifaddrs() catches on quickly....  */
65 
66 #include <errno.h>
67 #include <stdio.h>
68 #include <sys/socket.h>
69 #include <sys/ioctl.h>
70 #include <net/if.h>
71 #include <netinet/in.h>
72 
73 #if (defined(sun) || defined(__sun__)) && !defined(SIOCGIFCONF)
74 /* Sun puts socket ioctls in another file.  */
75 #include <sys/sockio.h>
76 #endif
77 
78 #define INIT 0xc3
79 
80 int
main(void)81 main(void)
82 {
83     char buffer[2048];
84     int i, sock, t, olen = -9, omod = -9;
85     struct ifconf ifc;
86     int gap = -1, lastgap = -1;
87 
88     sock = socket (AF_INET, SOCK_DGRAM, 0);
89     if (sock < 0) {
90         perror ("socket");
91         exit (1);
92     }
93     printf ("sizeof(struct if_req)=%d\n", sizeof (struct ifreq));
94     for (t = 0; t < sizeof (buffer); t++) {
95         ifc.ifc_len = t;
96         ifc.ifc_buf = buffer;
97         memset (buffer, INIT, sizeof (buffer));
98         i = ioctl (sock, SIOCGIFCONF, (char *) &ifc);
99         if (i < 0) {
100             /* Solaris returns "Invalid argument" if the buffer is too
101                small.  AIX and Linux return no error indication.  */
102             int e = errno;
103             snprintf (buffer, sizeof(buffer), "SIOCGIFCONF(%d)", t);
104             errno = e;
105             perror (buffer);
106             if (e == EINVAL)
107                 continue;
108             fprintf (stderr, "exiting on unexpected error\n");
109             exit (1);
110         }
111         i = sizeof (buffer) - 1;
112         while (buffer[i] == ((char)INIT) && i >= 0)
113             i--;
114         if (omod != i) {
115             /* Okay... the gap computed on the *last* iteration is the
116                largest for that particular size of returned data.
117                Save it, and then start computing gaps for the next
118                bigger size of returned data.  If we never get anything
119                bigger back, we discard the newer value and only keep
120                LASTGAP because all we care about is how much slop we
121                need to "prove" that there really weren't any more
122                entries to be returned.  */
123             if (gap > lastgap)
124                 lastgap = gap;
125         }
126         gap = t - i - 1;
127         if (olen != ifc.ifc_len || omod != i) {
128             printf ("ifc_len in = %4d, ifc_len out = %4d, last mod = %4d\n",
129                     t, ifc.ifc_len, i);
130             olen = ifc.ifc_len;
131             omod = i;
132         }
133     }
134     printf ("finished at ifc_len %d\n", t);
135     printf ("largest gap = %d\n", lastgap);
136     exit (0);
137 }
138