summaryrefslogtreecommitdiff
path: root/net/isc-dhcp40-server/files/patch-common::discover.c
blob: 1cfcc2094098929d8b07e7ba31aa5e0c7092bc34 (plain) (blame)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
--- common/discover.c.orig	Fri Jul 25 21:44:15 2003
+++ common/discover.c	Fri Mar  5 23:33:04 2004
@@ -47,6 +47,7 @@
 #endif /* not lint */
 
 #include "dhcpd.h"
+#include <ifaddrs.h>
 #include <sys/ioctl.h>
 
 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
@@ -135,10 +136,7 @@
 {
 	struct interface_info *tmp, *ip;
 	struct interface_info *last, *next;
-	char buf [2048];
-	struct ifconf ic;
-	struct ifreq ifr;
-	int i;
+	struct ifaddrs *ifap, *ifa;
 	int sock;
 	int address_count = 0;
 	struct subnet *subnet;
@@ -157,61 +155,6 @@
 	if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
 		log_fatal ("Can't create addrlist socket");
 
-	/* Get the interface configuration information... */
-
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	/* linux will only tell us how long a buffer it wants if we give it
-	 * a null buffer first. So, do a dry run to figure out the length.
-	 * 
-	 * XXX this code is duplicated from below because trying to fold
-	 * the logic into the if statement and goto resulted in excesssive
-	 * obfuscation. The intent is that unless you run Linux you shouldn't
-	 * have to deal with this. */
-
-	ic.ifc_len = 0;
-	ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
-#else
-	/* otherwise, we just feed it a starting size, and it'll tell us if
-	 * it needs more */
-
-	ic.ifc_len = sizeof buf;
-	ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-#endif
-
-      gifconf_again:
-	i = ioctl(sock, SIOCGIFCONF, &ic);
-
-	if (i < 0)
-		log_fatal ("ioctl: SIOCGIFCONF: %m");
-
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	/* Workaround for SIOCGIFCONF bug on some Linux versions. */
-	if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
-		ic.ifc_len = sizeof buf;
-		ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-		goto gifconf_again;
-	}
-#endif
-
-	/* If the SIOCGIFCONF resulted in more data than would fit in
-	   a buffer, allocate a bigger buffer. */
-	if ((ic.ifc_ifcu.ifcu_buf == buf 
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	     || ic.ifc_ifcu.ifcu_buf == 0
-#endif
-		) && ic.ifc_len > sizeof buf) {
-		ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
-		if (!ic.ifc_ifcu.ifcu_buf)
-			log_fatal ("Can't allocate SIOCGIFCONF buffer.");
-		goto gifconf_again;
-#ifdef SIOCGIFCONF_ZERO_PROBE
-	} else if (ic.ifc_ifcu.ifcu_buf == 0) {
-		ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
-		ic.ifc_len = sizeof buf;
-		goto gifconf_again;
-#endif
-	}
-
 		
 	/* If we already have a list of interfaces, and we're running as
 	   a DHCP server, the interfaces were requested. */
@@ -224,51 +167,38 @@
 	else
 		ir = INTERFACE_REQUESTED;
 
+	if (getifaddrs(&ifap) != 0)
+		log_fatal ("getifaddrs failed");
+
 	/* Cycle through the list of interfaces looking for IP addresses. */
-	for (i = 0; i < ic.ifc_len;) {
-		struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
-#ifdef HAVE_SA_LEN
-		if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
-			i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
-		else
-#endif
-			i += sizeof *ifp;
+	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
 
 #ifdef ALIAS_NAMES_PERMUTED
-		if ((s = strrchr (ifp -> ifr_name, ':'))) {
+		if ((s = strrchr (ifa -> ifa_name, ':'))) {
 			*s = 0;
 		}
 #endif
 
 #ifdef SKIP_DUMMY_INTERFACES
-		if (!strncmp (ifp -> ifr_name, "dummy", 5))
+		if (!strncmp (ifa -> ifa_name, "dummy", 5))
 			continue;
 #endif
 
-
-		/* See if this is the sort of interface we want to
-		   deal with. */
-		strcpy (ifr.ifr_name, ifp -> ifr_name);
-		if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
-			log_fatal ("Can't get interface flags for %s: %m",
-			       ifr.ifr_name);
-
 		/* See if we've seen an interface that matches this one. */
 		for (tmp = interfaces; tmp; tmp = tmp -> next)
-			if (!strcmp (tmp -> name, ifp -> ifr_name))
+			if (!strcmp (tmp -> name, ifa -> ifa_name))
 				break;
 
-		/* Skip non broadcast interfaces (plus loopback and
-		   point-to-point in case an OS incorrectly marks them
-		   as broadcast). Also skip down interfaces unless we're
+		/* See if this is the sort of interface we want to
+		   deal with.  Skip loopback, point-to-point and down
+		   interfaces, except don't skip down interfaces if we're
 		   trying to get a list of configurable interfaces. */
-		if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
-		      ifr.ifr_flags & IFF_LOOPBACK ||
-		      ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
-		    (!(ifr.ifr_flags & IFF_UP) &&
+		if ((ifa->ifa_flags & IFF_LOOPBACK) ||
+		     (ifa->ifa_flags & IFF_POINTOPOINT) ||
+		     (!(ifa->ifa_flags & IFF_UP) &&
 		     state != DISCOVER_UNCONFIGURED))
 			continue;
-		
+
 		/* If there isn't already an interface by this name,
 		   allocate one. */
 		if (!tmp) {
@@ -276,9 +206,9 @@
 			status = interface_allocate (&tmp, MDL);
 			if (status != ISC_R_SUCCESS)
 				log_fatal ("Error allocating interface %s: %s",
-					   ifp -> ifr_name,
+					   ifa -> ifa_name,
 					   isc_result_totext (status));
-			strcpy (tmp -> name, ifp -> ifr_name);
+			strcpy (tmp -> name, ifa -> ifa_name);
 			interface_snorf (tmp, ir);
 			interface_dereference (&tmp, MDL);
 			tmp = interfaces; /* XXX */
@@ -290,9 +220,9 @@
 		/* If we have the capability, extract link information
 		   and record it in a linked list. */
 #ifdef HAVE_AF_LINK
-		if (ifp -> ifr_addr.sa_family == AF_LINK) {
+		if (ifa -> ifa_addr->sa_family == AF_LINK) {
 			struct sockaddr_dl *foo = ((struct sockaddr_dl *)
-						   (&ifp -> ifr_addr));
+						   (ifa -> ifa_addr));
 #if defined (HAVE_SIN_LEN)
 			tmp -> hw_address.hlen = foo -> sdl_alen;
 #else
@@ -305,12 +235,11 @@
 		} else
 #endif /* AF_LINK */
 
-		if (ifp -> ifr_addr.sa_family == AF_INET) {
+		if (ifa -> ifa_addr->sa_family == AF_INET) {
 			struct iaddr addr;
 
 			/* Get a pointer to the address... */
-			memcpy (&foo, &ifp -> ifr_addr,
-				sizeof ifp -> ifr_addr);
+			bcopy(ifa->ifa_addr, &foo, sizeof(foo));
 
 			/* We don't want the loopback interface. */
 			if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
@@ -323,16 +252,15 @@
 			   found, keep a pointer to ifreq structure in
 			   which we found it. */
 			if (!tmp -> ifp) {
-#ifdef HAVE_SA_LEN
-				unsigned len = ((sizeof ifp -> ifr_name) +
-						ifp -> ifr_addr.sa_len);
-#else
-				unsigned len = sizeof *ifp;
-#endif
+
+				int len = (IFNAMSIZ +
+					ifa -> ifa_addr->sa_len);
 				tif = (struct ifreq *)dmalloc (len, MDL);
 				if (!tif)
 					log_fatal ("no space for ifp.");
-				memcpy (tif, ifp, len);
+				strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ);
+				memcpy(&tif->ifr_addr, ifa->ifa_addr,
+					ifa->ifa_addr->sa_len);
 				tmp -> ifp = tif;
 				tmp -> primary_address = foo.sin_addr;
 			}
@@ -346,9 +274,6 @@
 		}
 	}
 
-	/* If we allocated a buffer, free it. */
-	if (ic.ifc_ifcu.ifcu_buf != buf)
-		dfree (ic.ifc_ifcu.ifcu_buf, MDL);
 
 #if defined (LINUX_SLASHPROC_DISCOVERY)
 	/* On Linux, interfaces that don't have IP addresses don't
@@ -529,6 +454,7 @@
 	   be able to configure, we can quit now. */
 	if (state == DISCOVER_UNCONFIGURED) {
 		close (sock);
+		freeifaddrs(ifap);
 		return;
 	}
 
@@ -674,6 +600,7 @@
 	}
 
 	close (sock);
+	freeifaddrs(ifap);
 
 	if (state == DISCOVER_SERVER && wifcount == 0) {
 		log_info ("%s", "");