72
72
#define MAX_IFACES 4
73
#define LOOPBACK "lo" // XXX: We would have a problem with something like "loa0".
74
74
#ifndef INET_ADDRSTRLEN
75
75
#define INET_ADDRSTRLEN 16
80
*-----------------------------------------------------------------------------
82
* ValidateConvertAddress --
84
* Helper routine validates an address as a return value for
85
* NetUtil_GetPrimaryIP.
88
* Returns TRUE with sufficient result stored in outputBuffer on success.
89
* Returns FALSE with "" stored in outputBuffer on failure.
94
*-----------------------------------------------------------------------------
98
ValidateConvertAddress(const char *ifaceName, // IN: interface name
99
const struct sockaddr_in *addr, // IN: network address to
101
char ipstr[INET_ADDRSTRLEN]) // OUT: converted address
105
* 1. Ensure this isn't a loopback device.
106
* 2. Ensure this is an (IPv4) internet address.
108
if (ifaceName[0] == '\0' ||
109
strncmp(ifaceName, LOOPBACK, sizeof LOOPBACK - 1) == 0 ||
110
addr->sin_family != AF_INET) {
115
* Branches separated because it just looked really silly to lump the
116
* initial argument checking and actual conversion logic together.
120
* 3. Attempt network to presentation conversion.
121
* 4. Ensure the IP isn't all zeros.
123
if (inet_ntop(AF_INET, (void *)&addr->sin_addr, ipstr, INET_ADDRSTRLEN) != NULL &&
124
strcmp(ipstr, "0.0.0.0") != 0) {
80
135
*----------------------------------------------------------------------
82
137
* NetUtil_GetPrimaryIP --
84
139
* Get the primary IP for this machine.
88
* The IP or NULL if an error occurred.
142
* If applicable address found, returns string of said IP address.
143
* If applicable address not found, returns an empty string.
144
* If an error occurred, returns NULL.
147
* Caller is responsible for free()ing returned string.
94
149
*----------------------------------------------------------------------
102
157
struct ifconf iflist;
103
158
struct ifreq ifaces[MAX_IFACES];
159
char ipstr[INET_ADDRSTRLEN] = "";
106
161
/* Get a socket descriptor to give to ioctl(). */
107
162
sd = socket(PF_INET, SOCK_STREAM, 0);
112
167
memset(&iflist, 0, sizeof iflist);
119
174
if (ioctl(sd, SIOCGIFCONF, &iflist) < 0) {
126
181
/* Loop through the list of interfaces provided by ioctl(). */
127
182
for (i = 0; i < (sizeof ifaces/sizeof *ifaces); i++) {
129
* Find the first interface whose name is not blank and isn't a
130
* loopback device. This should be the primary interface.
132
if ((*ifaces[i].ifr_name != '\0') &&
133
(strncmp(ifaces[i].ifr_name, LOOPBACK, strlen(LOOPBACK)) != 0)) {
134
struct sockaddr_in *addr;
137
* Allocate memory to return to caller; they must free this if we
138
* don't return error.
140
ipstr = calloc(1, INET_ADDRSTRLEN);
145
addr = (struct sockaddr_in *)(&ifaces[i].ifr_addr);
147
/* Convert this address to dotted decimal */
148
if (inet_ntop(AF_INET, (void *)&addr->sin_addr,
149
ipstr, INET_ADDRSTRLEN) == NULL) {
153
/* We'd rather return NULL than an IP of zeros. */
154
if (strcmp(ipstr, "0.0.0.0") == 0) {
183
if (ValidateConvertAddress(ifaces[i].ifr_name,
184
(struct sockaddr_in *)&ifaces[i].ifr_addr,
162
/* Making it through loop means no non-loopback devices were found. */
190
/* Success. Here, caller, you can throw this away. */
191
return strdup(ipstr);
171
194
#else /* } FreeBSD || APPLE { */
193
212
* We traverse the list until there are no more interfaces or we have found
194
213
* the primary interface. This function defines the primary interface to be
195
214
* the first non-loopback, internet interface in the interface list.
197
216
for(curr = ifaces; curr != NULL; curr = curr->ifa_next) {
198
struct sockaddr_in *addr;
200
/* Ensure this isn't a loopback device. */
201
if (strncmp(curr->ifa_name, LOOPBACK, strlen(LOOPBACK)) == 0) {
205
addr = (struct sockaddr_in *)(curr->ifa_addr);
207
/* Ensure this is an (IPv4) internet interface. */
208
if (addr->sin_family == AF_INET) {
209
memset(ipstr, 0, sizeof ipstr);
211
/* Attempt network to presentation conversion. */
212
if (inet_ntop(AF_INET, (void *)&addr->sin_addr, ipstr, sizeof ipstr) == NULL) {
216
/* If the IP is all zeros we'll try for another interface. */
217
if (strcmp(ipstr, "0.0.0.0") == 0) {
218
/* Empty the string so we never return "0.0.0.0". */
224
* We have found the primary interface and its dotted-decimal IP is
217
if (ValidateConvertAddress(curr->ifa_name,
218
(struct sockaddr_in *)curr->ifa_addr,
231
224
/* Tell FreeBSD to free our linked list. */
232
225
freeifaddrs(ifaces);
235
* If ipstr is blank, just return NULL. Otherwise, we create a copy of the
236
* string and return the pointer; the caller must free this memory.
238
return (ipstr[0] == '\0') ? NULL : strdup(ipstr);
227
/* Success. Here, caller, you can throw this away. */
228
return strdup(ipstr);