]> Pileus Git - ~andy/fetchmail/blob - interface.c
Don't rely on snprintf.
[~andy/fetchmail] / interface.c
1 /*
2  * interface.c -- implements fetchmail 'interface' and 'monitor' commands
3  *
4  * This module was implemented by George M. Sipe <gsipe@pobox.com>
5  * or <gsipe@acm.org> and is:
6  *
7  *      Copyright (c) 1996,1997 by George M. Sipe
8  *
9  *      FreeBSD specific portions written by and Copyright (c) 1999 
10  *      Andy Doran <ad@psn.ie>.
11  *
12  * This is free software; you can redistribute it and/or modify it under
13  * the terms of the GNU General Public License as published by the Free
14  * Software Foundation; version 2, or (at your option) any later version.
15  */
16 #include <sys/types.h>
17 #include <sys/param.h>
18
19 #if (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__)
20
21 #include "config.h"
22 #include <stdio.h>
23 #include <string.h>
24 #if defined(STDC_HEADERS)
25 #include <stdlib.h>
26 #endif
27 #if defined(HAVE_UNISTD_H)
28 #include <unistd.h>
29 #endif
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <net/if.h>
35 #if defined(__FreeBSD__)
36 #if defined __FreeBSD_USE_KVM
37     #if __FreeBSD_version >= 300001
38         #include <net/if_var.h>
39     #endif
40     #include <kvm.h>
41     #include <nlist.h>
42     #include <sys/fcntl.h>
43 #else
44     #include <sys/sysctl.h>
45     #include <net/route.h>
46     #include <net/if_dl.h>
47 #endif
48 #endif
49 #include "config.h"
50 #include "fetchmail.h"
51 #include "socket.h"
52 #include "i18n.h"
53 #include "tunable.h"
54
55 typedef struct {
56         struct in_addr addr, dstaddr, netmask;
57         int rx_packets, tx_packets;
58 } ifinfo_t;
59
60 struct interface_pair_s {
61         struct in_addr interface_address;
62         struct in_addr interface_mask;
63 } *interface_pair;
64
65 static char *netdevfmt;
66
67 /*
68  * Count of packets to see on an interface before monitor considers it up.
69  * Needed because when pppd shuts down the link, the packet counts go up
70  * by two (one rx and one tx?, maybe).  A value of 2 seems to do the trick,
71  * but we'll give it some extra.
72  */
73 #define MONITOR_SLOP            5
74
75 #if defined(linux)
76
77 void interface_init(void)
78 /* figure out which /proc/dev/net format to use */
79 {
80     FILE *fp = popen("uname -r", "r");  /* still wins if /proc is out */
81
82     /* pre-linux-2.2 format -- transmit packet count in 8th field */
83     netdevfmt = "%d %d %*d %*d %*d %d %*d %d %*d %*d %*d %*d %d";
84
85     if (!fp)
86         return;
87     else
88     {
89         int major, minor;
90
91         if (fscanf(fp, "%d.%d.%*d", &major, &minor) >= 2
92                                         && major >= 2 && minor >= 2)
93             /* Linux 2.2 -- transmit packet count in 10th field */
94             netdevfmt = "%d %d %*d %*d %*d %d %*d %*d %*d %d %*d %*d %d";
95         pclose(fp);
96     }
97 }
98
99 static int _get_ifinfo_(int socket_fd, FILE *stats_file, const char *ifname,
100                 ifinfo_t *ifinfo)
101 /* get active network interface information - return non-zero upon success */
102 {
103         int namelen = strlen(ifname);
104         struct ifreq request;
105         char *cp, buffer[256];
106         int found = 0;
107         int counts[4];
108
109         /* initialize result */
110         memset((char *) ifinfo, 0, sizeof(ifinfo_t));
111
112         /* get the packet I/O counts */
113         while (fgets(buffer, sizeof(buffer) - 1, stats_file)) {
114                 for (cp = buffer; *cp && *cp == ' '; ++cp);
115                 if (!strncmp(cp, ifname, namelen) &&
116                                 cp[namelen] == ':') {
117                         cp += namelen + 1;
118                         if (sscanf(cp, netdevfmt,
119                                    counts, counts+1, counts+2, 
120                                    counts+3,&found)>4) { /* found = dummy */
121                                 /* newer kernel with byte counts */
122                                 ifinfo->rx_packets=counts[1];
123                                 ifinfo->tx_packets=counts[3];
124                         } else {
125                                 /* older kernel, no byte counts */
126                                 ifinfo->rx_packets=counts[0];
127                                 ifinfo->tx_packets=counts[2];
128                         }
129                         found = 1;
130                 }
131         }
132         if (!found) return (FALSE);
133
134         /* see if the interface is up */
135         strcpy(request.ifr_name, ifname);
136         if (ioctl(socket_fd, SIOCGIFFLAGS, &request) < 0)
137                 return(FALSE);
138         if (!(request.ifr_flags & IFF_RUNNING))
139                 return(FALSE);
140
141         /* get the (local) IP address */
142         strcpy(request.ifr_name, ifname);
143         if (ioctl(socket_fd, SIOCGIFADDR, &request) < 0)
144                 return(FALSE);
145         ifinfo->addr = ((struct sockaddr_in *) (&request.ifr_addr))->sin_addr;
146
147         /* get the PPP destination (remote) IP address */
148         ifinfo->dstaddr.s_addr = 0;
149         strcpy(request.ifr_name, ifname);
150         if (ioctl(socket_fd, SIOCGIFDSTADDR, &request) >= 0)
151                 ifinfo->dstaddr = ((struct sockaddr_in *)
152                                         (&request.ifr_dstaddr))->sin_addr;
153
154         /* get the netmask */
155         strcpy(request.ifr_name, ifname);
156         if (ioctl(socket_fd, SIOCGIFNETMASK, &request) >= 0) {
157           ifinfo->netmask = ((struct sockaddr_in *)
158                              (&request.ifr_netmask))->sin_addr;
159           return (TRUE);
160         }
161
162         return(FALSE);
163 }
164
165 static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
166 {
167         int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
168         FILE *stats_file = fopen("/proc/net/dev", "r");
169         int result;
170
171         if (socket_fd < 0 || !stats_file)
172                 result = FALSE;
173         else
174         {
175             char        *sp = strchr(ifname, '/');
176
177             if (sp)
178                 *sp = '\0';
179             result = _get_ifinfo_(socket_fd, stats_file, ifname, ifinfo);
180             if (sp)
181                 *sp = '/';
182         }
183         if (socket_fd >= 0)
184             SockClose(socket_fd);
185         if (stats_file)
186             fclose(stats_file); /* not checking should be safe, mode was "r" */
187         return(result);
188 }
189
190 #elif defined __FreeBSD__
191
192 #if defined __FreeBSD_USE_KVM
193
194 static kvm_t *kvmfd;
195 static struct nlist symbols[] = 
196 {
197         {"_ifnet"},
198         {NULL}
199 };
200 static u_long   ifnet_savedaddr;
201 static gid_t    if_rgid;
202 static gid_t    if_egid;
203
204 void 
205 interface_set_gids(gid_t egid, gid_t rgid)
206 {
207         if_rgid = rgid;
208         if_egid = egid;
209 }
210
211 static int 
212 openkvm(void)
213 {
214         if ((kvmfd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
215                 return FALSE;
216         
217         if (kvm_nlist(kvmfd, symbols) < 0)
218                 return FALSE;
219            
220         if (kvm_read(kvmfd, (unsigned long) symbols[0].n_value, &ifnet_savedaddr, sizeof(unsigned long)) == -1)
221                 return FALSE;
222                 
223         return TRUE;
224 }
225
226 static int 
227 get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
228 {
229         char                    tname[16];
230         char                    iname[16];
231         struct ifnet            ifnet;
232         unsigned long           ifnet_addr = ifnet_savedaddr;
233 #if __FreeBSD_version >= 300001
234         struct ifnethead        ifnethead;
235         struct ifaddrhead       ifaddrhead;
236 #endif
237         struct ifaddr           ifaddr;
238         unsigned long           ifaddr_addr;
239         struct sockaddr         sa;
240         unsigned long           sa_addr;
241         uint                    i;
242         
243         if (if_egid)
244                 setegid(if_egid);
245         
246         for (i = 0; ifname[i] && ifname[i] != '/'; i++)
247                 iname[i] = ifname[i];
248                 
249         iname[i] = '\0';
250         
251         if (!kvmfd)
252         {
253                 if (!openkvm())
254                 {
255                         report(stderr, 0, _("Unable to open kvm interface. Make sure fetchmail is SGID kmem."));
256                         if (if_egid)
257                                 setegid(if_rgid);
258                         exit(1);
259                 }
260         }
261
262 #if __FreeBSD_version >= 300001
263         kvm_read(kvmfd, ifnet_savedaddr, (char *) &ifnethead, sizeof ifnethead);
264         ifnet_addr = (u_long) ifnethead.tqh_first;
265 #else
266         ifnet_addr = ifnet_savedaddr;
267 #endif
268
269         while (ifnet_addr)
270         {
271                 kvm_read(kvmfd, ifnet_addr, &ifnet, sizeof(ifnet));
272                 kvm_read(kvmfd, (unsigned long) ifnet.if_name, tname, sizeof tname);
273 #ifdef HAVE_SNPRINTF
274                 snprintf(tname, sizeof tname - 1,
275 #else
276                 sprintf(tname,
277 #endif
278                         "%s%d", tname, ifnet.if_unit);
279
280                 if (!strcmp(tname, iname))
281                 {
282                         if (!(ifnet.if_flags & IFF_UP))
283                         {
284                                 if (if_egid)
285                                         setegid(if_rgid);
286                                 return 0;
287                         }
288                                 
289                         ifinfo->rx_packets = ifnet.if_ipackets;
290                         ifinfo->tx_packets = ifnet.if_opackets;
291
292 #if __FreeBSD_version >= 300001
293                         ifaddr_addr = (u_long) ifnet.if_addrhead.tqh_first;
294 #else
295                         ifaddr_addr = (u_long) ifnet.if_addrlist;
296 #endif
297                         
298                         while(ifaddr_addr)
299                         {
300                                 kvm_read(kvmfd, ifaddr_addr, &ifaddr, sizeof(ifaddr));
301                                 kvm_read(kvmfd, (u_long)ifaddr.ifa_addr, &sa, sizeof(sa));
302                                 
303                                 if (sa.sa_family != AF_INET)
304                                 {
305 #if __FreeBSD_version >= 300001
306                                         ifaddr_addr = (u_long) ifaddr.ifa_link.tqe_next;
307 #else
308                                         ifaddr_addr = (u_long) ifaddr.ifa_next;
309 #endif
310                                         continue;
311                                 }
312                         
313                                 ifinfo->addr.s_addr = *(u_long *)(sa.sa_data + 2);
314                                 kvm_read(kvmfd, (u_long)ifaddr.ifa_dstaddr, &sa, sizeof(sa));
315                                 ifinfo->dstaddr.s_addr = *(u_long *)(sa.sa_data + 2);
316                                 kvm_read(kvmfd, (u_long)ifaddr.ifa_netmask, &sa, sizeof(sa));
317                                 ifinfo->netmask.s_addr = *(u_long *)(sa.sa_data + 2);
318
319                                 if (if_egid)
320                                         setegid(if_rgid);
321
322                                 return 1;
323                         }
324                         
325                         if (if_egid)
326                                 setegid(if_rgid);
327                         
328                         return 0;
329                 }
330
331 #if __FreeBSD_version >= 300001
332                 ifnet_addr = (u_long) ifnet.if_link.tqe_next;
333 #else
334                 ifnet_addr = (unsigned long) ifnet.if_next;
335 #endif
336         }
337
338         if (if_egid)
339                 setegid(if_rgid);
340         
341         return 0;
342 }
343
344 #else /* Do not use KVM on FreeBSD */
345
346 /*
347  * Expand the compacted form of addresses as returned via the
348  * configuration read via sysctl().
349  */
350
351 static void
352 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
353 {
354     struct sockaddr *sa;
355     int i;
356
357 #define ROUNDUP(a) \
358         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
359 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
360
361     memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
362     for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
363         if ((rtinfo->rti_addrs & (1 << i)) == 0)
364             continue;
365         rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
366         ADVANCE(cp, sa);
367     }
368
369 #undef ROUNDUP
370 #undef ADVANCE
371 }
372
373 static int
374 get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
375 {
376     uint                i;
377     int                 rc = 0;
378     int                 ifindex = -1;
379     size_t              needed;
380     char                *buf = NULL;
381     char                *lim = NULL;
382     char                *next = NULL;
383     struct if_msghdr    *ifm;
384     struct ifa_msghdr   *ifam;
385     struct sockaddr_in  *sin;
386     struct sockaddr_dl  *sdl;
387     struct rt_addrinfo  info;
388     char                iname[16];
389     int                 mib[6];
390
391     memset(ifinfo, 0, sizeof(ifinfo));
392
393     /* trim interface name */
394
395     for (i = 0; i < sizeof(iname) && ifname[i] && ifname[i] != '/'; i++)
396         iname[i] = ifname[i];
397         
398     if (i == 0 || i == sizeof(iname))
399     {
400         report(stderr, _("Unable to parse interface name from %s"), ifname);
401         return 0;
402     }
403
404     iname[i] = 0;
405
406
407     /* get list of existing interfaces */
408
409     mib[0] = CTL_NET;
410     mib[1] = PF_ROUTE;
411     mib[2] = 0;
412     mib[3] = AF_INET;           /* Only IP addresses please. */
413     mib[4] = NET_RT_IFLIST;
414     mib[5] = 0;                 /* List all interfaces. */
415
416
417     /* Get interface data. */
418
419     if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
420     {
421         report(stderr, 
422             _("get_ifinfo: sysctl (iflist estimate) failed"));
423         exit(1);
424     }
425     if ((buf = malloc(needed)) == NULL)
426     {
427         report(stderr, 
428             _("get_ifinfo: malloc failed"));
429         exit(1);
430     }
431     if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
432     {
433         report(stderr, 
434             _("get_ifinfo: sysctl (iflist) failed"));
435         exit(1);
436     }
437
438     lim = buf+needed;
439
440
441     /* first look for the interface information */
442
443     next = buf;
444     while (next < lim)
445     {
446         ifm = (struct if_msghdr *)next;
447         next += ifm->ifm_msglen;
448
449         if (ifm->ifm_version != RTM_VERSION) 
450         {
451             report(stderr, 
452                 _("Routing message version %d not understood."),
453                 ifm->ifm_version);
454             exit(1);
455         }
456
457         if (ifm->ifm_type == RTM_IFINFO)
458         {
459             sdl = (struct sockaddr_dl *)(ifm + 1);
460
461             if (!(strlen(iname) == sdl->sdl_nlen 
462                 && strncmp(iname, sdl->sdl_data, sdl->sdl_nlen) == 0))
463             {
464                 continue;
465             }
466
467             if ( !(ifm->ifm_flags & IFF_UP) )
468             {
469                 /* the interface is down */
470                 goto get_ifinfo_end;
471             }
472
473             ifindex = ifm->ifm_index;
474             ifinfo->rx_packets = ifm->ifm_data.ifi_ipackets;
475             ifinfo->tx_packets = ifm->ifm_data.ifi_opackets;
476
477             break;
478         }
479     }
480
481     if (ifindex < 0)
482     {
483         /* we did not find an interface with a matching name */
484         report(stderr, _("No interface found with name %s"), iname);
485         goto get_ifinfo_end;
486     }
487
488     /* now look for the interface's IP address */
489
490     next = buf;
491     while (next < lim)
492     {
493         ifam = (struct ifa_msghdr *)next;
494         next += ifam->ifam_msglen;
495
496         if (ifindex > 0
497             && ifam->ifam_type == RTM_NEWADDR
498             && ifam->ifam_index == ifindex)
499         {
500             /* Expand the compacted addresses */
501             info.rti_addrs = ifam->ifam_addrs;
502             rt_xaddrs((char *)(ifam + 1), 
503                         ifam->ifam_msglen + (char *)ifam,
504                         &info);
505
506             /* Check for IPv4 address information only */
507             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
508             {
509                 continue;
510             }
511
512             rc = 1;
513
514             sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
515             if (sin)
516             {
517                 ifinfo->addr = sin->sin_addr;
518             }
519
520             sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
521             if (!sin)
522             {
523                 ifinfo->netmask = sin->sin_addr;
524             }
525
526             /* note: RTAX_BRD contains the address at the other
527              * end of a point-to-point link or the broadcast address
528              * of non point-to-point link
529              */
530             sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
531             if (!sin)
532             {
533                 ifinfo->dstaddr = sin->sin_addr;
534             }
535
536             break;
537         }
538     }
539
540     if (rc == 0)
541     {
542         report(stderr, _("No IP address found for %s"), iname);
543     }
544
545 get_ifinfo_end:
546     free(buf);
547     return rc;
548 }
549
550 #endif /* __FREEBSD_USE_SYSCTL_GET_IFFINFO */
551
552 #endif /* defined __FreeBSD__ */
553
554
555 #ifndef HAVE_INET_ATON
556 /*
557  * Note: This is not a true replacement for inet_aton(), as it won't
558  * do the right thing on "255.255.255.255" (which translates to -1 on
559  * most machines).  Fortunately this code will be used only if you're
560  * on an older Linux that lacks a real implementation.
561  */
562 #ifdef HAVE_NETINET_IN_SYSTM_H
563 # include <sys/types.h>
564 # include <netinet/in_systm.h>
565 #endif
566
567 #include <netinet/in.h>
568 #include <netinet/ip.h>
569 #include <arpa/inet.h>
570 #include <string.h>
571
572 static int inet_aton(const char *cp, struct in_addr *inp) {
573     long addr;
574
575     addr = inet_addr(cp);
576     if (addr == ((long) -1)) return 0;
577
578     memcpy(inp, &addr, sizeof(addr));
579     return 1;
580 }
581 #endif /* HAVE_INET_ATON */
582
583 void interface_parse(char *buf, struct hostdata *hp)
584 /* parse 'interface' specification */
585 {
586         char *cp1, *cp2;
587
588         hp->interface = xstrdup(buf);
589
590         /* find and isolate just the IP address */
591         if (!(cp1 = strchr(buf, '/')))
592         {
593                 (void) report(stderr,
594                               _("missing IP interface address\n"));
595                 exit(PS_SYNTAX);
596         }
597         *cp1++ = '\000';
598
599         /* find and isolate just the netmask */
600         if (!(cp2 = strchr(cp1, '/')))
601                 cp2 = "255.255.255.255";
602         else
603                 *cp2++ = '\000';
604
605         /* convert IP address and netmask */
606         hp->interface_pair = (struct interface_pair_s *)xmalloc(sizeof(struct interface_pair_s));
607         if (!inet_aton(cp1, &hp->interface_pair->interface_address))
608         {
609                 (void) report(stderr,
610                               _("invalid IP interface address\n"));
611                 exit(PS_SYNTAX);
612         }
613         if (!inet_aton(cp2, &hp->interface_pair->interface_mask))
614         {
615                 (void) report(stderr,
616                               _("invalid IP interface mask\n"));
617                 exit(PS_SYNTAX);
618         }
619         /* apply the mask now to the IP address (range) required */
620         hp->interface_pair->interface_address.s_addr &=
621                 hp->interface_pair->interface_mask.s_addr;
622
623         /* restore original interface string (for configuration dumper) */
624         *--cp1 = '/';
625         return;
626 }
627
628 void interface_note_activity(struct hostdata *hp)
629 /* save interface I/O counts */
630 {
631         ifinfo_t ifinfo;
632         struct query *ctl;
633
634         /* if not monitoring link, all done */
635         if (!hp->monitor)
636                 return;
637
638         /* get the current I/O stats for the monitored link */
639         if (get_ifinfo(hp->monitor, &ifinfo))
640                 /* update this and preceeding host entries using the link
641                    (they were already set during this pass but the I/O
642                    count has now changed and they need to be re-updated)
643                 */
644                 for (ctl = querylist; ctl; ctl = ctl->next) {
645                         if (ctl->server.monitor && !strcmp(hp->monitor, ctl->server.monitor))
646                                 ctl->server.monitor_io =
647                                         ifinfo.rx_packets + ifinfo.tx_packets;
648                         /* do NOT update host entries following this one */
649                         if (&ctl->server == hp)
650                                 break;
651                 }
652
653 #ifdef  ACTIVITY_DEBUG
654         (void) report(stdout, 
655                       _("activity on %s -noted- as %d\n"), 
656                       hp->monitor, hp->monitor_io);
657 #endif
658 }
659
660 int interface_approve(struct hostdata *hp, flag domonitor)
661 /* return TRUE if OK to poll, FALSE otherwise */
662 {
663         ifinfo_t ifinfo;
664
665         /* check interface IP address (range), if specified */
666         if (hp->interface) {
667                 /* get interface info */
668                 if (!get_ifinfo(hp->interface, &ifinfo)) {
669                         (void) report(stdout, 
670                                       _("skipping poll of %s, %s down\n"),
671                                       hp->pollname, hp->interface);
672                         return(FALSE);
673                 }
674                 /* check the IP addresses (range) */
675                 if      (!(
676                                 /* check remote IP address */
677                                 ((ifinfo.dstaddr.s_addr != 0) &&
678                                 (ifinfo.dstaddr.s_addr &
679                                 hp->interface_pair->interface_mask.s_addr) ==
680                                 hp->interface_pair->interface_address.s_addr)
681                                 ||
682                                 /* check local IP address */
683                                 ((ifinfo.addr.s_addr &
684                                 hp->interface_pair->interface_mask.s_addr) ==
685                                 hp->interface_pair->interface_address.s_addr)
686                         ) )
687                 {
688                         (void) report(stdout,
689                                 _("skipping poll of %s, %s IP address excluded\n"),
690                                 hp->pollname, hp->interface);
691                         return(FALSE);
692                 }
693         }
694
695         /* if not monitoring link, all done */
696         if (!domonitor || !hp->monitor)
697                 return(TRUE);
698
699 #ifdef  ACTIVITY_DEBUG
700         (void) report(stdout, 
701                       _("activity on %s checked as %d\n"), 
702                       hp->monitor, hp->monitor_io);
703 #endif
704         /* if monitoring, check link for activity if it is up */
705         if (get_ifinfo(hp->monitor, &ifinfo))
706         {
707             int diff = (ifinfo.rx_packets + ifinfo.tx_packets)
708                                                         - hp->monitor_io;
709
710             /*
711              * There are three cases here:
712              *
713              * (a) If the new packet count is less than the recorded one,
714              * probably pppd was restarted while fetchmail was running.
715              * Don't skip.
716              *
717              * (b) newpacket count is greater than the old packet count,
718              * but the difference is small and may just reflect the overhead
719              * of a link shutdown.  Skip.
720              *
721              * (c) newpacket count is greater than the old packet count,
722              * and the difference is large. Connection is live.  Don't skip.
723              */
724             if (diff >= 0 && diff <= MONITOR_SLOP)
725             {
726                 (void) report(stdout, 
727                               _("skipping poll of %s, %s inactive\n"),
728                               hp->pollname, hp->monitor);
729                 return(FALSE);
730             }
731         }
732
733 #ifdef ACTIVITY_DEBUG
734        report(stdout, _("activity on %s was %d, is %d\n"),
735              hp->monitor, hp->monitor_io,
736              ifinfo.rx_packets + ifinfo.tx_packets);
737 #endif
738
739         return(TRUE);
740 }
741 #endif /* (defined(linux) && !defined(INET6_ENABLE)) || defined(__FreeBSD__) */