source: npl/internetserver/dhcp/dhcommon-getifaddrs.patch @ 17a9f19

Last change on this file since 17a9f19 was ebc5ae5, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

upgraded dhcpd to 4.3.6 for better ipv6 support

  • Property mode set to 100644
File size: 10.5 KB
RevLine 
[ebc5ae5]1description: use getifaddrs() system call, rather than parsing /proc/net on linux
2author: Jiri Popelka <jpopelka@redhat.com>
3origin: http://pkgs.fedoraproject.org/cgit/dhcp.git/tree/dhcp-getifaddrs.patch?id=d12e0eb05e510268ce9b8dcb839e27d5eca9aff5
4bug-debian: https://bugs.debian.org/605657
5bug-ubuntu: https://bugs.launchpad.net/ubuntu/+source/isc-dhcp/+bug/1446767
6bug-fedora: https://bugzilla.redhat.com/show_bug.cgi?id=449946
7
8--- a/common/discover.c
9+++ b/common/discover.c
10@@ -373,392 +373,13 @@ end_iface_scan(struct iface_conf_list *i
11        ifaces->sock = -1;
12 }
13 
14-#elif __linux /* !HAVE_SIOCGLIFCONF */
15-/*
16- * Linux support
17- * -------------
18- *
19- * In Linux, we use the /proc pseudo-filesystem to get information
20- * about interfaces, along with selected ioctl() calls.
21- *
22- * Linux low level access is documented in the netdevice man page.
23- */
24-
25-/*
26- * Structure holding state about the scan.
27- */
28-struct iface_conf_list {
29-       int sock;       /* file descriptor used to get information */
30-       FILE *fp;       /* input from /proc/net/dev */
31-#ifdef DHCPv6
32-       FILE *fp6;      /* input from /proc/net/if_inet6 */
33-#endif
34-};
35-
36-/*
37- * Structure used to return information about a specific interface.
38- */
39-struct iface_info {
40-       char name[IFNAMSIZ];            /* name of the interface, e.g. "eth0" */
41-       struct sockaddr_storage addr;   /* address information */
42-       isc_uint64_t flags;             /* interface flags, e.g. IFF_LOOPBACK */
43-};
44-
45-/*
46- * Start a scan of interfaces.
47- *
48- * The iface_conf_list structure maintains state for this process.
49- */
50-int
51-begin_iface_scan(struct iface_conf_list *ifaces) {
52-       char buf[IF_LINE_LENGTH];
53-       int len;
54-       int i;
55-
56-       ifaces->fp = fopen("/proc/net/dev", "r");
57-       if (ifaces->fp == NULL) {
58-               log_error("Error opening '/proc/net/dev' to list interfaces");
59-               return 0;
60-       }
61-
62-       /*
63-        * The first 2 lines are header information, so read and ignore them.
64-        */
65-       for (i=0; i<2; i++) {
66-               if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
67-                       log_error("Error reading headers from '/proc/net/dev'");
68-                       fclose(ifaces->fp);
69-                       ifaces->fp = NULL;
70-                       return 0;
71-               }
72-               len = strlen(buf);
73-               if ((len <= 0) || (buf[len-1] != '\n')) {
74-                       log_error("Bad header line in '/proc/net/dev'");
75-                       fclose(ifaces->fp);
76-                       ifaces->fp = NULL;
77-                       return 0;
78-               }
79-       }
80-
81-       ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
82-       if (ifaces->sock < 0) {
83-               log_error("Error creating socket to list interfaces; %m");
84-               fclose(ifaces->fp);
85-               ifaces->fp = NULL;
86-               return 0;
87-       }
88-
89-#ifdef DHCPv6
90-       if (local_family == AF_INET6) {
91-               ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
92-               if (ifaces->fp6 == NULL) {
93-                       log_error("Error opening '/proc/net/if_inet6' to "
94-                                 "list IPv6 interfaces; %m");
95-                       close(ifaces->sock);
96-                       ifaces->sock = -1;
97-                       fclose(ifaces->fp);
98-                       ifaces->fp = NULL;
99-                       return 0;
100-               }
101-       }
102-#endif
103-
104-       return 1;
105-}
106-
107-/*
108- * Read our IPv4 interfaces from /proc/net/dev.
109- *
110- * The file looks something like this:
111- *
112- * Inter-|   Receive ...
113- *  face |bytes    packets errs drop fifo frame ...
114- *     lo: 1580562    4207    0    0    0     0 ...
115- *   eth0:       0       0    0    0    0     0 ...
116- *   eth1:1801552440   37895    0   14    0     ...
117- *
118- * We only care about the interface name, which is at the start of
119- * each line.
120- *
121- * We use an ioctl() to get the address and flags for each interface.
122- */
123-static int
124-next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
125-       char buf[IF_LINE_LENGTH];
126-       int len;
127-       char *p;
128-       char *name;
129-       struct ifreq tmp;
130-
131-       /*
132-        * Loop exits when we find an interface that has an address, or
133-        * when we run out of interfaces.
134-        */
135-       for (;;) {
136-               do {
137-                       /*
138-                        *  Read the next line in the file.
139-                        */
140-                       if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
141-                               if (ferror(ifaces->fp)) {
142-                                       *err = 1;
143-                                       log_error("Error reading interface "
144-                                               "information");
145-                               } else {
146-                                       *err = 0;
147-                               }
148-                               return 0;
149-                       }
150-
151-                       /*
152-                        * Make sure the line is a nice,
153-                        * newline-terminated line.
154-                        */
155-                       len = strlen(buf);
156-                       if ((len <= 0) || (buf[len-1] != '\n')) {
157-                               log_error("Bad line reading interface "
158-                                         "information");
159-                               *err = 1;
160-                               return 0;
161-                       }
162-
163-                       /*
164-                        * Figure out our name.
165-                        */
166-                       p = strrchr(buf, ':');
167-                       if (p == NULL) {
168-                               log_error("Bad line reading interface "
169-                                         "information (no colon)");
170-                               *err = 1;
171-                               return 0;
172-                       }
173-                       *p = '\0';
174-                       name = buf;
175-                       while (isspace(*name)) {
176-                               name++;
177-                       }
178-
179-                       /*
180-                        * Copy our name into our interface structure.
181-                        */
182-                       len = p - name;
183-                       if (len >= sizeof(info->name)) {
184-                               *err = 1;
185-                               log_error("Interface name '%s' too long", name);
186-                               return 0;
187-                       }
188-                       strncpy(info->name, name, sizeof(info->name) - 1);
189-
190-#ifdef ALIAS_NAMED_PERMUTED
191-                       /* interface aliases look like "eth0:1" or "wlan1:3" */
192-                       s = strchr(info->name, ':');
193-                       if (s != NULL) {
194-                               *s = '\0';
195-                       }
196-#endif
197-
198-#ifdef SKIP_DUMMY_INTERFACES
199-               } while (strncmp(info->name, "dummy", 5) == 0);
200-#else
201-               } while (0);
202-#endif
203-
204-               memset(&tmp, 0, sizeof(tmp));
205-               strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
206-               if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) {
207-                       if (errno == EADDRNOTAVAIL) {
208-                               continue;
209-                       }
210-                       log_error("Error getting interface address "
211-                                 "for '%s'; %m", name);
212-                       *err = 1;
213-                       return 0;
214-               }
215-               memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
216-
217-               memset(&tmp, 0, sizeof(tmp));
218-               strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
219-               if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
220-                       log_error("Error getting interface flags for '%s'; %m",
221-                               name);
222-                       *err = 1;
223-                       return 0;
224-               }
225-               info->flags = tmp.ifr_flags;
226-
227-               *err = 0;
228-               return 1;
229-       }
230-}
231-
232-#ifdef DHCPv6
233-/*
234- * Read our IPv6 interfaces from /proc/net/if_inet6.
235- *
236- * The file looks something like this:
237- *
238- * fe80000000000000025056fffec00008 05 40 20 80   vmnet8
239- * 00000000000000000000000000000001 01 80 10 80       lo
240- * fe80000000000000025056fffec00001 06 40 20 80   vmnet1
241- * 200108881936000202166ffffe497d9b 03 40 00 00     eth1
242- * fe8000000000000002166ffffe497d9b 03 40 20 80     eth1
243- *
244- * We get IPv6 address from the start, the interface name from the end,
245- * and ioctl() to get flags.
246- */
247-static int
248-next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
249-       char buf[IF_LINE_LENGTH];
250-       int len;
251-       char *p;
252-       char *name;
253-       int i;
254-       struct sockaddr_in6 addr;
255-       struct ifreq tmp;
256-
257-       do {
258-               /*
259-                *  Read the next line in the file.
260-                */
261-               if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) {
262-                       if (ferror(ifaces->fp6)) {
263-                               *err = 1;
264-                               log_error("Error reading IPv6 "
265-                                         "interface information");
266-                       } else {
267-                               *err = 0;
268-                       }
269-                       return 0;
270-               }
271-
272-               /*
273-                * Make sure the line is a nice, newline-terminated line.
274-                */
275-               len = strlen(buf);
276-               if ((len <= 0) || (buf[len-1] != '\n')) {
277-                       log_error("Bad line reading IPv6 "
278-                                 "interface information");
279-                       *err = 1;
280-                       return 0;
281-               }
282-
283-               /*
284-                * Figure out our name.
285-                */
286-               buf[--len] = '\0';
287-               p = strrchr(buf, ' ');
288-               if (p == NULL) {
289-                       log_error("Bad line reading IPv6 interface "
290-                                 "information (no space)");
291-                       *err = 1;
292-                       return 0;
293-               }
294-               name = p+1;
295-
296-               /*
297-                * Copy our name into our interface structure.
298-                */
299-               len = strlen(name);
300-               if (len >= sizeof(info->name)) {
301-                       *err = 1;
302-                       log_error("IPv6 interface name '%s' too long", name);
303-                       return 0;
304-               }
305-               strncpy(info->name, name, sizeof(info->name) - 1);
306-
307-#ifdef SKIP_DUMMY_INTERFACES
308-       } while (strncmp(info->name, "dummy", 5) == 0);
309-#else
310-       } while (0);
311-#endif
312-
313-       /*
314-        * Double-check we start with the IPv6 address.
315-        */
316-       for (i=0; i<32; i++) {
317-               if (!isxdigit(buf[i]) || isupper(buf[i])) {
318-                       *err = 1;
319-                       log_error("Bad line reading IPv6 interface address "
320-                                 "for '%s'", name);
321-                       return 0;
322-               }
323-       }
324-
325-       /*
326-        * Load our socket structure.
327-        */
328-       memset(&addr, 0, sizeof(addr));
329-       addr.sin6_family = AF_INET6;
330-       for (i=0; i<16; i++) {
331-               unsigned char byte;
332-                static const char hex[] = "0123456789abcdef";
333-                byte = ((index(hex, buf[i * 2]) - hex) << 4) |
334-                       (index(hex, buf[i * 2 + 1]) - hex);
335-               addr.sin6_addr.s6_addr[i] = byte;
336-       }
337-       memcpy(&info->addr, &addr, sizeof(addr));
338-
339-       /*
340-        * Get our flags.
341-        */
342-       memset(&tmp, 0, sizeof(tmp));
343-       strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
344-       if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
345-               log_error("Error getting interface flags for '%s'; %m", name);
346-               *err = 1;
347-               return 0;
348-       }
349-       info->flags = tmp.ifr_flags;
350-
351-       *err = 0;
352-       return 1;
353-}
354-#endif /* DHCPv6 */
355-
356-/*
357- * Retrieve the next interface.
358- *
359- * Returns information in the info structure.
360- * Sets err to 1 if there is an error, otherwise 0.
361- */
362-int
363-next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
364-       memset(info, 0, sizeof(struct iface_info));
365-       if (next_iface4(info, err, ifaces)) {
366-               return 1;
367-       }
368-#ifdef DHCPv6
369-       if (!(*err)) {
370-               if (local_family == AF_INET6)
371-                       return next_iface6(info, err, ifaces);
372-       }
373-#endif
374-       return 0;
375-}
376-
377-/*
378- * End scan of interfaces.
379- */
380-void
381-end_iface_scan(struct iface_conf_list *ifaces) {
382-       fclose(ifaces->fp);
383-       ifaces->fp = NULL;
384-       close(ifaces->sock);
385-       ifaces->sock = -1;
386-#ifdef DHCPv6
387-       if (local_family == AF_INET6) {
388-               fclose(ifaces->fp6);
389-               ifaces->fp6 = NULL;
390-       }
391-#endif
392-}
393 #else
394 
395 /*
396- * BSD support
397+ * Unix support
398  * -----------
399  *
400- * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs()
401+ * FreeBSD, NetBSD, OpenBSD, Linux, and OS X all have the getifaddrs()
402  * function.
403  *
404  * The getifaddrs() man page describes the use.
405@@ -806,6 +427,8 @@ begin_iface_scan(struct iface_conf_list
406  */
407 int
408 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
409+       size_t sa_len = 0;
410+
411        if (ifaces->next == NULL) {
412                *err = 0;
413                return 0;
414@@ -818,8 +441,20 @@ next_iface(struct iface_info *info, int
415        }
416        memset(info, 0, sizeof(struct iface_info));
417        strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1);
418-       memcpy(&info->addr, ifaces->next->ifa_addr,
419-              ifaces->next->ifa_addr->sa_len);
420+
421+       memset(&info->addr, 0 , sizeof(info->addr));
422+
423+       if (ifaces->next->ifa_addr != NULL) {
424+#ifdef HAVE_SA_LEN
425+               sa_len = ifaces->next->ifa_addr->sa_len;
426+#else
427+               if (ifaces->next->ifa_addr->sa_family == AF_INET)
428+                       sa_len = sizeof(struct sockaddr_in);
429+               else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
430+                       sa_len = sizeof(struct sockaddr_in6);
431+#endif
432+               memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
433+       }
434        info->flags = ifaces->next->ifa_flags;
435        ifaces->next = ifaces->next->ifa_next;
436        *err = 0;
Note: See TracBrowser for help on using the repository browser.