summaryrefslogtreecommitdiff
path: root/sbin/ipf/ifaddr.c
blob: 3f162c361a3d83dc1019dc29d5752a2fcaac2c3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/* $OpenBSD: ifaddr.c,v 1.5 2000/04/05 05:35:28 kjell Exp $ */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <err.h>
#include <stdlib.h>
#include <unistd.h>
#include "ifaddr.h"


/*
 * if_addr():
 *      given a string containing an interface name (e.g. "ppp0")
 *      return the IP address it represents
 *
 * The OpenBSD community considers this feature to be quite useful and
 * suggests inclusion into other platforms. The closest alternative is
 * to define /etc/networks with suitable values.
 */
int     if_addr(name, ap)
char            *name;
struct in_addr  *ap;
{
        struct ifconf ifc;
        struct ifreq ifreq, *ifr;
        char *inbuf = NULL;
        int s, i, len = 8192;

        if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
                warn("socket");
                return 0;
        }

        while (1) {
                ifc.ifc_len = len;
                ifc.ifc_buf = inbuf = realloc(inbuf, len);
                if (inbuf == NULL)
                        err(1, "malloc");
                if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
                        warn("SIOCGIFCONF");
                        goto if_addr_lose;
                }
                if (ifc.ifc_len + sizeof(ifreq) < len)
                        break;
                len *= 2;
        }
        ifr = ifc.ifc_req;
        ifreq.ifr_name[0] = '\0';
        for (i = 0; i < ifc.ifc_len; ) {
                ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
                i += sizeof(ifr->ifr_name) +
                        (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
                                ? ifr->ifr_addr.sa_len
                                : sizeof(struct sockaddr));
                ifreq = *ifr;
                if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) < 0)
                        continue;
                if (ifr->ifr_addr.sa_family != AF_INET)
                        continue;
                if (!strcmp(name, ifr->ifr_name)) {
                        struct sockaddr_in *sin;
                        close(s);
                        free(inbuf);
                        sin = (struct sockaddr_in *)&ifr->ifr_addr;
                        *ap = sin->sin_addr;
                        return (1);
                }
        }

if_addr_lose:
        close(s);
        free(inbuf);
        return 0;
}