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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
/* Refrences:
* https://lists.samba.org/archive/samba-technical/2009-February/063079.html
* http://stackoverflow.com/questions/4139405/#4139811
* https://github.com/steve-o/openpgm/blob/master/openpgm/pgm/getifaddrs.c
*/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include "ifaddrs.h"
#define MAX(x,y) ((x)>(y)?(x):(y))
#define SIZE(p) MAX((p).ss_len,sizeof(p))
static struct sockaddr *
sa_dup (struct sockaddr_storage *sa1)
{
struct sockaddr *sa2;
size_t sz = sizeof(struct sockaddr_storage);
sa2 = (struct sockaddr *) calloc(1,sz);
memcpy(sa2,sa1,sz);
return(sa2);
}
void freeifaddrs (struct ifaddrs *ifp)
{
if (NULL == ifp) return;
free(ifp->ifa_name);
free(ifp->ifa_addr);
free(ifp->ifa_netmask);
free(ifp->ifa_dstaddr);
freeifaddrs(ifp->ifa_next);
free(ifp);
}
int getifaddrs (struct ifaddrs **ifap)
{
int sd = -1;
char *ccp, *ecp;
struct lifconf ifc;
struct lifreq *ifr;
struct lifnum lifn;
struct ifaddrs *cifa = NULL; /* current */
struct ifaddrs *pifa = NULL; /* previous */
const size_t IFREQSZ = sizeof(struct lifreq);
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
goto error;
ifc.lifc_buf = NULL;
*ifap = NULL;
/* find how much memory to allocate for the SIOCGLIFCONF call */
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = 0;
if (ioctl(sd, SIOCGLIFNUM, &lifn) < 0)
goto error;
/* Sun and Apple code likes to pad the interface count here in case interfaces
* are coming up between calls */
lifn.lifn_count += 4;
ifc.lifc_family = AF_UNSPEC;
ifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq);
ifc.lifc_buf = calloc(1, ifc.lifc_len);
if (ioctl(sd, SIOCGLIFCONF, &ifc) < 0)
goto error;
ccp = (char *)ifc.lifc_req;
ecp = ccp + ifc.lifc_len;
while (ccp < ecp) {
ifr = (struct lifreq *) ccp;
cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs));
cifa->ifa_next = NULL;
cifa->ifa_name = strdup(ifr->lifr_name);
if (pifa == NULL) *ifap = cifa; /* first one */
else pifa->ifa_next = cifa;
if (ioctl(sd, SIOCGLIFADDR, ifr, IFREQSZ) < 0)
goto error;
cifa->ifa_addr = sa_dup(&ifr->lifr_addr);
if (ioctl(sd, SIOCGLIFNETMASK, ifr, IFREQSZ) < 0)
goto error;
cifa->ifa_netmask = sa_dup(&ifr->lifr_addr);
cifa->ifa_flags = 0;
cifa->ifa_dstaddr = NULL;
if (0 == ioctl(sd, SIOCGLIFFLAGS, ifr)) /* optional */
cifa->ifa_flags = ifr->lifr_flags;
if (ioctl(sd, SIOCGLIFDSTADDR, ifr, IFREQSZ) < 0) {
if (0 == ioctl(sd, SIOCGLIFBRDADDR, ifr, IFREQSZ))
cifa->ifa_dstaddr = sa_dup(&ifr->lifr_addr);
}
else cifa->ifa_dstaddr = sa_dup(&ifr->lifr_addr);
pifa = cifa;
ccp += IFREQSZ;
}
free(ifc.lifc_buf);
close(sd);
return 0;
error:
if (ifc.lifc_buf != NULL)
free(ifc.lifc_buf);
if (sd != -1)
close(sd);
freeifaddrs(*ifap);
return (-1);
}
|