Пример #1
0
/*
 * BSD 4.4 defines the size of an ifreq to be
 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
 * However, under earlier systems, sa_len isn't present, so the size is 
 * just sizeof(struct ifreq).
 */
#ifdef HAVE_SA_LEN
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
#define ifreq_size(i) max(sizeof(struct ifreq),\
     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
#else
#define ifreq_size(i) sizeof(struct ifreq)
#endif /* HAVE_SA_LEN*/


#ifdef SIOCGLIFCONF /* Solaris */
static int
get_lifconf (int af, int s, size_t *lenp, char *buf)
    /*@modifies *buf,*lenp@*/
{
    int ret;
    struct lifconf lifc;

    lifc.lifc_family = af;
    lifc.lifc_flags = 0;
    lifc.lifc_len = *lenp;
    lifc.lifc_buf = buf;
    memset(buf, 0, *lenp);

    ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
    if (ret)
	Tperror ("SIOCGLIFCONF");

    *lenp = lifc.lifc_len;
    return ret;
}
Пример #2
0
/* #include <net/if6.h> */
static int
get_if_laddrconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
/*@modifies *buf,*lenp@*/
{
    int ret;
    struct if_laddrconf iflc;

    /*@+matchanyintegral@*/
    iflc.iflc_len = *lenp;
    /*@=matchanyintegral@*/
    iflc.iflc_buf = buf;
    memset(buf, 0, *lenp);
    /*@-moduncon@*/
    ret = ioctl (s, SIOCGLIFCONF, (char *)&iflc);
    if (ret)
        Tperror ("SIOCGLIFCONF");
    /*@=moduncon@*/
    /*@+matchanyintegral@*/
    *lenp = iflc.iflc_len;
    /*@=matchanyintegral@*/
    return ret;
}
Пример #3
0
static int
get_lifconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
/*@modifies *buf,*lenp@*/
{
    int ret;
    struct lifconf lifc;

    lifc.lifc_family = af;
    lifc.lifc_flags = 0;
    /*@+matchanyintegral@*/
    lifc.lifc_len = *lenp;
    /*@=matchanyintegral@*/
    lifc.lifc_buf = buf;
    memset(buf, 0, *lenp);
    /*@-moduncon@*/
    ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
    if (ret)
        Tperror ("SIOCGLIFCONF");
    /*@=moduncon@*/
    /*@+matchanyintegral@*/
    *lenp = lifc.lifc_len;
    /*@=matchanyintegral@*/
    return ret;
}
Пример #4
0
int
foreach_localaddr (void *data,
		   int (*pass1fn) (void *, struct sockaddr *),
		   int (*betweenfn) (void *),
		   int (*pass2fn) (void *, struct sockaddr *))
{
    /* Okay, this is kind of odd.  We have to use each of the address
       families we care about, because with an AF_INET socket, extra
       interfaces like hme0:1 that have only AF_INET6 addresses will
       cause errors.  Similarly, if hme0 has more AF_INET addresses
       than AF_INET6 addresses, we won't be able to retrieve all of
       the AF_INET addresses if we use an AF_INET6 socket.  Since
       neither family is guaranteed to have the greater number of
       addresses, we should use both.

       If it weren't for this little quirk, we could use one socket of
       any type, and ask for addresses of all types.  At least, it
       seems to work that way.  */

    /* Solaris kerberos: avoid using AF_NS if no define */
#if defined (KRB5_USE_INET6) && defined (KRB5_USE_NS)
    static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
#elif defined (KRB5_USE_INET6)
    static const int afs[] = { AF_INET, AF_INET6 };
#else
    static const int afs[] = { AF_INET };
#endif
    
#define N_AFS (sizeof (afs) / sizeof (afs[0]))
    struct {
	int af;
	int sock;
	void *buf;
	size_t buf_size;
	struct lifnum lifnum;
    } afp[N_AFS];
    int code, i, j;
    int retval = 0, afidx;
    krb5_error_code sock_err = 0;
    struct lifreq *lifr, lifreq, *lifr2;

#define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
#define P (afp[afidx])

    KRB5_LOG0(KRB5_INFO, "foreach_localaddr() start");
    /* init */
    FOREACH_AF () {
	P.af = afs[afidx];
	P.sock = -1;
	P.buf = 0;
    }

    /* first pass: get raw data, discard uninteresting addresses, callback */
    FOREACH_AF () {
	KRB5_LOG (KRB5_INFO, "foreach_localaddr() trying af %d", P.af);
	P.sock = socket (P.af, USE_TYPE, USE_PROTO);
	if (P.sock < 0) {
	    sock_err = SOCKET_ERROR;
	    Tperror ("socket");
	    continue;
	}

	P.lifnum.lifn_family = P.af;
	P.lifnum.lifn_flags = 0;
	P.lifnum.lifn_count = 0;
	code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum);
	if (code) {
	    Tperror ("ioctl(SIOCGLIFNUM)");
	    retval = errno;
	    goto punt;
	}

	KRB5_LOG (KRB5_INFO, "foreach_localaddr() lifn_count %d",
		P.lifnum.lifn_count);
	P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2;
	P.buf = malloc (P.buf_size);
	if (P.buf == NULL) {
	    retval = errno;
	    goto punt;
	}

	code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf);
	if (code < 0) {
	    retval = errno;
	    goto punt;
	}

	for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) {
	    /*LINTED*/
	    lifr = (struct lifreq *)((caddr_t) P.buf+i);

	    strncpy(lifreq.lifr_name, lifr->lifr_name,
		    sizeof (lifreq.lifr_name));
	    KRB5_LOG (KRB5_INFO, "foreach_localaddr() interface %s",
		    lifreq.lifr_name);
	    /* ioctl unknown to lclint */
	    if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
		Tperror ("ioctl(SIOCGLIFFLAGS)");
	    skip:
		KRB5_LOG (KRB5_INFO, 
			"foreach_localaddr() skipping interface %s",
			lifr->lifr_name);
		/* mark for next pass */
		lifr->lifr_name[0] = '\0';
		continue;
	    }

#ifdef IFF_LOOPBACK
	    /* None of the current callers want loopback addresses.  */
	    if (lifreq.lifr_flags & IFF_LOOPBACK) {
		Tprintf (("  loopback\n"));
		goto skip;
	    }
#endif
	    /* Ignore interfaces that are down.  */
	    if ((lifreq.lifr_flags & IFF_UP) == 0) {
		Tprintf (("  down\n"));
		goto skip;
	    }

	    /* Make sure we didn't process this address already.  */
	    for (j = 0; j < i; j += sizeof (*lifr2)) {
		/*LINTED*/
		lifr2 = (struct lifreq *)((caddr_t) P.buf+j);
		if (lifr2->lifr_name[0] == '\0')
		    continue;
		if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family
		    /* Compare address info.  If this isn't good enough --
		       i.e., if random padding bytes turn out to differ
		       when the addresses are the same -- then we'll have
		       to do it on a per address family basis.  */
		    && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr,
				sizeof (*lifr))) {
		    Tprintf (("  duplicate addr\n"));
		    KRB5_LOG0 (KRB5_INFO, "foreach_localaddr() dup addr");
		    goto skip;
		}
	    }

	    if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr)))
		goto punt;
	}
    }

    /* Did we actually get any working sockets?  */
    FOREACH_AF ()
	if (P.sock != -1)
	    goto have_working_socket;
    retval = sock_err;
    goto punt;
have_working_socket:

    if (betweenfn != NULL && (*betweenfn)(data))
	goto punt;

    if (pass2fn)
	FOREACH_AF ()
	    if (P.sock >= 0) {
		for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) {
		    /*LINTED*/
		    lifr = (struct lifreq *)((caddr_t) P.buf+i);

		    if (lifr->lifr_name[0] == '\0')
			/* Marked in first pass to be ignored.  */
			continue;

		    KRB5_LOG (KRB5_INFO,
			    "foreach_localaddr() doing pass2fn i = %d",
			    i);
		    if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr)))
			goto punt;
		}
	    }
punt:
    FOREACH_AF () {
	closesocket(P.sock);
	free (P.buf);
    }

    return retval;
}