* t_gifconf.c: New file
authorKen Raeburn <raeburn@mit.edu>
Sat, 31 Mar 2001 06:33:48 +0000 (06:33 +0000)
committerKen Raeburn <raeburn@mit.edu>
Sat, 31 Mar 2001 06:33:48 +0000 (06:33 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13127 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/ChangeLog
src/lib/krb5/os/t_gifconf.c [new file with mode: 0644]

index 8647ce0b82a38bbeb85489ff71154179a87f4804..ceff3a62c8c8c49942bb9533cbea533fd6672057 100644 (file)
@@ -1,3 +1,7 @@
+2001-03-31  Ken Raeburn  <raeburn@mit.edu>
+
+       * t_gifconf.c: New file.
+
 2001-03-10  Ezra Peisach  <epeisach@mit.edu>
 
        * def_realm.c: Move prototype for krb5_try_realm_txt_rr() to
diff --git a/src/lib/krb5/os/t_gifconf.c b/src/lib/krb5/os/t_gifconf.c
new file mode 100644 (file)
index 0000000..1fd0d05
--- /dev/null
@@ -0,0 +1,127 @@
+/* SIOCGIFCONF:
+
+   The behavior of this ioctl varies across systems.
+
+   The "largest gap" values are the largest number of bytes I've seen
+   left unused at the end of the supplied buffer when there were more
+   entries to return.  These values may of coures be dependent on the
+   configurations of the particular systems I was testing with.
+
+   NetBSD 1.5-alpha: The returned ifc_len is the desired amount of
+   space, always.  The returned list may be truncated if there isn't
+   enough room; no overrun.  Largest gap: 43.  (NetBSD now has
+   getifaddrs.)
+
+   Solaris 2.7: Return EINVAL if the buffer space is too small for all
+   the data to be returned, including ifc_len==0.  Solaris is the only
+   system I've found so far that actually returns an error.  No gap.
+
+   Linux 2.2.12 (RH 6.1 dist, x86): The buffer is filled in with as
+   many entries as will fit, and the size used is returned in ifc_len.
+   The list is truncated if needed, with no indication.  Largest gap: 31.
+
+   IRIX 6.5: The buffer is filled in with as many entries as will fit
+   in N-1 bytes, and the size used is returned in ifc_len.  Providing
+   exactly the desired number of bytes is inadequate; the buffer must
+   be *bigger* than needed.  (E.g., 32->0, 33->32.)  The returned
+   ifc_len is always less than the supplied one.  Largest gap: 32.
+
+   AIX 4.3.3: Sometimes the returned ifc_len is bigger than the
+   supplied one, but it may not be big enough for *all* the
+   interfaces.  Sometimes it's smaller than the supplied value, even
+   if the returned list is truncated.  The list is filled in with as
+   many entries as will fit; no overrun.  Largest gap: 143.
+
+   Older AIX: We're told by W. David Shambroom <DShambroom@gte.com> in
+   PR krb5-kdc/919 that older versions of AIX have a bug in the
+   SIOCGIFCONF ioctl which can cause them to overrun the supplied
+   buffer.  However, we don't yet have details as to which version,
+   whether the overrun amount was bounded (e.g., one ifreq's worth) or
+   not, whether it's a real buffer overrun or someone assuming it was
+   because ifc_len was increased, etc.  Once we've got details, we can
+   try to work around the problem.
+
+   Digital UNIX 4.0F: If input ifc_len is zero, return an ifc_len
+   that's big enough to include all entries.  (Actually, on our
+   system, it appears to be larger than that by 32.)  If input ifc_len
+   is nonzero, fill in as many entries as will fit, and set ifc_len
+   accordingly.  (Tested only with INIT of zero.)
+
+   So... if the returned ifc_len is bigger than the supplied one,
+   we'll need at least that much space -- but possibly more -- to hold
+   all the results.  If the returned value is smaller or the same, we
+   may still need more space.
+
+   Using this ioctl is going to be messy.  Let's just hope that
+   getifaddrs() catches on quickly....  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#if (defined(sun) || defined(__sun__)) && !defined(SIOCGIFCONF)
+/* Sun puts socket ioctls in another file.  */
+#include <sys/sockio.h>
+#endif
+
+#define INIT 0xc3
+
+int main () {
+    char buffer[2048];
+    int i, sock, t, olen = -9, omod = -9;
+    struct ifconf ifc;
+    int gap = -1, lastgap = -1;
+
+    sock = socket (AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+       perror ("socket");
+       exit (1);
+    }
+    printf ("sizeof(struct if_req)=%d\n", sizeof (struct ifreq));
+    for (t = 0; t < sizeof (buffer); t++) {
+       ifc.ifc_len = t;
+       ifc.ifc_buf = buffer;
+       memset (buffer, INIT, sizeof (buffer));
+       i = ioctl (sock, SIOCGIFCONF, (char *) &ifc);
+       if (i < 0) {
+           /* Solaris returns "Invalid argument" if the buffer is too
+              small.  AIX and Linux return no error indication.  */
+           int e = errno;
+           sprintf (buffer, "SIOCGIFCONF(%d)", t);
+           errno = e;
+           perror (buffer);
+           if (e == EINVAL)
+               continue;
+           fprintf (stderr, "exiting on unexpected error\n");
+           exit (1);
+       }
+       i = sizeof (buffer) - 1;
+       while (buffer[i] == ((char)INIT) && i >= 0)
+           i--;
+       if (omod != i) {
+           /* Okay... the gap computed on the *last* iteration is the
+              largest for that particular size of returned data.
+              Save it, and then start computing gaps for the next
+              bigger size of returned data.  If we never get anything
+              bigger back, we discard the newer value and only keep
+              LASTGAP because all we care about is how much slop we
+              need to "prove" that there really weren't any more
+              entries to be returned.  */
+           if (gap > lastgap)
+               lastgap = gap;
+       }
+       gap = t - i - 1;
+       if (olen != ifc.ifc_len || omod != i) {
+           printf ("ifc_len in = %4d, ifc_len out = %4d, last mod = %4d\n",
+                   t, ifc.ifc_len, i);
+           olen = ifc.ifc_len;
+           omod = i;
+       }
+    }
+    printf ("finished at ifc_len %d\n", t);
+    printf ("largest gap = %d\n", lastgap);
+    exit (0);
+}