]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/address_conf.c
Fix getnameinfo() for FreeBSD fixes bug #2083
[bacula/bacula] / bacula / src / lib / address_conf.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *   Configuration file parser for IP-Addresse ipv4 and ipv6
21  *
22  *     Written by Meno Abels, June MMIV
23  *
24  */
25
26
27 #include "bacula.h"
28 #ifdef HAVE_ARPA_NAMESER_H
29 #include <arpa/nameser.h>
30 #endif
31 #ifdef HAVE_RESOLV_H
32 //#include <resolv.h>
33 #endif
34
35 static int add_address(dlist **out, IPADDR::i_type type, unsigned short defaultport, int family,
36                 const char *hostname_str, const char *port_str, char *buf, int buflen);
37
38
39 IPADDR::IPADDR(const IPADDR &src) : type(src.type)
40 {
41   memcpy(&saddrbuf, &src.saddrbuf, sizeof(saddrbuf));
42   saddr  = &saddrbuf.dontuse;
43   saddr4 = &saddrbuf.dontuse4;
44 #ifdef HAVE_IPV6
45   saddr6 = &saddrbuf.dontuse6;
46 #endif
47 }
48
49 IPADDR::IPADDR(int af) : type(R_EMPTY)
50 {
51 #ifdef HAVE_IPV6
52   if (!(af == AF_INET6 || af == AF_INET)) {
53      Emsg1(M_ERROR_TERM, 0, _("Only ipv4 and ipv6 are supported (%d)\n"), af);
54   }
55 #else
56   if (af != AF_INET) {
57      Emsg1(M_ERROR_TERM, 0, _("Only ipv4 is supported (%d)\n"), af);
58   }
59 #endif
60   memset(&saddrbuf, 0, sizeof(saddrbuf));
61   saddr  = &saddrbuf.dontuse;
62   saddr4 = &saddrbuf.dontuse4;
63 #ifdef HAVE_IPV6
64   saddr6 = &saddrbuf.dontuse6;
65 #endif
66   saddr->sa_family = af;
67   if (af  == AF_INET) {
68      saddr4->sin_port = 0xffff;
69   }
70 #ifdef HAVE_IPV6
71   else {
72      saddr6->sin6_port = 0xffff;
73   }
74 #endif
75 #ifdef HAVE_SA_LEN
76 #ifdef HAVE_IPV6
77   saddr->sa_len = (af == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
78 #else
79   saddr->sa_len = sizeof(sockaddr_in);
80 #endif
81 #endif
82    set_addr_any();
83 }
84
85 void IPADDR::set_type(i_type o)
86 {
87    type = o;
88 }
89
90 IPADDR::i_type IPADDR::get_type() const
91 {
92    return type;
93 }
94
95 unsigned short IPADDR::get_port_net_order() const
96 {
97    unsigned short port = 0;
98    if (saddr->sa_family == AF_INET) {
99       port = saddr4->sin_port;
100    }
101 #ifdef HAVE_IPV6
102    else {
103       port = saddr6->sin6_port;
104    }
105 #endif
106     return port;
107 }
108
109 void IPADDR::set_port_net(unsigned short port)
110 {
111    if (saddr->sa_family == AF_INET) {
112       saddr4->sin_port = port;
113    }
114 #ifdef HAVE_IPV6
115    else {
116       saddr6->sin6_port = port;
117    }
118 #endif
119 }
120
121 int IPADDR::get_family() const
122 {
123     return saddr->sa_family;
124 }
125
126 /*
127  * Note, this returns the address of the socket structure
128  *  not the address of the socket address.
129  *  This socket address is a union of the different types
130  *  of sockets (IPv4, ...) available, so it is portable.
131  */
132 struct sockaddr *IPADDR::get_sockaddr()
133 {
134    return saddr;
135 }
136
137 int IPADDR::get_sockaddr_len()
138 {
139 #ifdef HAVE_IPV6
140    return saddr->sa_family == AF_INET ? sizeof(*saddr4) : sizeof(*saddr6);
141 #else
142    return sizeof(*saddr4);
143 #endif
144 }
145 void IPADDR::copy_addr(IPADDR *src)
146 {
147    if (saddr->sa_family == AF_INET) {
148       saddr4->sin_addr.s_addr = src->saddr4->sin_addr.s_addr;
149    }
150 #ifdef HAVE_IPV6
151    else if (saddr->sa_family == AF_INET6) {
152       saddr6->sin6_addr = src->saddr6->sin6_addr;
153    }
154 #endif
155 }
156
157 #ifdef NEED_IN6ADDR_ANY
158 /* The <netinet/in.h> header shall declare the following external variable
159  * On Oses such as Solaris, it requires to define also XPG4_2 and EXTENSIONS
160  * and we have no real idea on what it will change.
161  */
162 extern const struct in6_addr in6addr_any;
163 #endif
164
165 void IPADDR::set_addr_any()
166 {
167    if (saddr->sa_family == AF_INET) {
168       saddr4->sin_addr.s_addr = INADDR_ANY;
169    }
170 #ifdef HAVE_IPV6
171    else if (saddr->sa_family == AF_INET6) {
172      saddr6->sin6_addr = in6addr_any;
173    }
174 #endif
175 }
176
177 void IPADDR::set_addr4(struct in_addr *ip4)
178 {
179    if (saddr->sa_family != AF_INET) {
180       Emsg1(M_ERROR_TERM, 0, _("You tried to assign a ipv6 address to an ipv4(%d)\n"), saddr->sa_family);
181    }
182    saddr4->sin_addr = *ip4;
183 }
184
185 #ifdef HAVE_IPV6
186 void IPADDR::set_addr6(struct in6_addr *ip6)
187 {
188    if (saddr->sa_family != AF_INET6) {
189       Emsg1(M_ERROR_TERM, 0, _("You tried to assign an ipv4 address to an ipv6(%d)\n"), saddr->sa_family);
190    }
191    saddr6->sin6_addr = *ip6;
192 }
193 #endif
194
195 const char *IPADDR::get_address(char *outputbuf, int outlen)
196 {
197    outputbuf[0] = '\0';
198 #ifdef HAVE_INET_NTOP
199 # ifdef HAVE_IPV6
200    inet_ntop(saddr->sa_family, saddr->sa_family == AF_INET ?
201               (void*)&(saddr4->sin_addr) : (void*)&(saddr6->sin6_addr),
202               outputbuf, outlen);
203 # else
204    inet_ntop(saddr->sa_family, (void*)&(saddr4->sin_addr), outputbuf, outlen);
205 # endif
206 #else
207    bstrncpy(outputbuf, inet_ntoa(saddr4->sin_addr), outlen);
208 #endif
209    return outputbuf;
210 }
211
212 const char *IPADDR::build_address_str(char *buf, int blen)
213 {
214    char tmp[1024];
215    if (get_family() == AF_INET) {
216       bsnprintf(buf, blen, "%s:%hu ",
217                 get_address(tmp, sizeof(tmp) - 1), get_port_host_order());
218    } else {
219       bsnprintf(buf, blen, "[%s]:%hu ",
220                 get_address(tmp, sizeof(tmp) - 1), get_port_host_order());
221    }
222    return buf;
223 }
224
225 const char *build_addresses_str(dlist *addrs, char *buf, int blen)
226 {
227    if (!addrs || addrs->size() == 0) {
228       bstrncpy(buf, "", blen);
229       return buf;
230    }
231    char *work = buf;
232    IPADDR *p;
233    foreach_dlist(p, addrs) {
234       char tmp[1024];
235       int len = bsnprintf(work, blen, "%s", p->build_address_str(tmp, sizeof(tmp)));
236       if (len < 0)
237          break;
238       work += len;
239       blen -= len;
240    }
241    return buf;
242 }
243
244 const char *get_first_address(dlist *addrs, char *outputbuf, int outlen)
245 {
246    return ((IPADDR *)(addrs->first()))->get_address(outputbuf, outlen);
247 }
248
249 int get_first_port_net_order(dlist *addrs)
250 {
251    if (!addrs) {
252       return 0;
253    } else {
254       return ((IPADDR *)(addrs->first()))->get_port_net_order();
255    }
256 }
257
258 int get_first_port_host_order(dlist *addrs)
259 {
260    if (!addrs) {
261       return 0;
262    } else {
263       return ((IPADDR *)(addrs->first()))->get_port_host_order();
264    }
265 }
266
267 void init_default_addresses(dlist **addr_list, int port)
268 {
269    char buf[1024];
270    unsigned short sport = port;
271    if (!add_address(addr_list, IPADDR::R_DEFAULT, htons(sport), AF_INET, 0, 0, buf, sizeof(buf))) {
272       Emsg1(M_ERROR_TERM, 0, _("Can't add default IPv4 address (%s)\n"), buf);
273    }
274    Dmsg1(20, "Initaddr %s\n", build_addresses_str(*addr_list, buf, sizeof(buf)));
275
276 }
277
278 static int add_address(dlist **out, IPADDR::i_type type, unsigned short defaultport, int family,
279                 const char *hostname_str, const char *port_str, char *buf, int buflen)
280 {
281    IPADDR *iaddr;
282    IPADDR *jaddr;
283    dlist *hostaddrs;
284    unsigned short port;
285    IPADDR::i_type intype = type;
286
287    buf[0] = 0;
288    dlist *addrs = (dlist *)(*(out));
289    if (!addrs) {
290       IPADDR *tmp = 0;
291       addrs = *out = New(dlist(tmp, &tmp->link));
292    }
293
294    type = (type == IPADDR::R_SINGLE_PORT ||
295            type == IPADDR::R_SINGLE_ADDR) ? IPADDR::R_SINGLE : type;
296    if (type != IPADDR::R_DEFAULT) {
297       IPADDR *def = 0;
298       foreach_dlist(iaddr, addrs) {
299          if (iaddr->get_type() == IPADDR::R_DEFAULT) {
300             def = iaddr;
301          } else if (iaddr->get_type() != type) {
302             bsnprintf(buf, buflen,
303                       _("Old style addresses cannot be mixed with new style. Try removing Port=nnn."));
304             Dmsg1(20, "%s\n", buf);
305             return 0;
306          }
307       }
308       if (def) {
309          addrs->remove(def);
310          delete def;
311       }
312    }
313
314    if (!port_str || port_str[0] == '\0') {
315       port = defaultport;
316    } else {
317       int pnum = atol(port_str);
318       if (0 < pnum && pnum < 0xffff) {
319          port = htons(pnum);
320       } else {
321          struct servent *s = getservbyname(port_str, "tcp");
322          if (s) {
323             port = s->s_port;
324          } else {
325             bsnprintf(buf, buflen, _("Cannot resolve service(%s)"), port_str);
326             Dmsg1(20, "%s\n", buf);
327             return 0;
328          }
329       }
330    }
331
332    const char *myerrstr;
333    hostaddrs = bnet_host2ipaddrs(hostname_str, family, &myerrstr);
334    if (!hostaddrs) {
335       bsnprintf(buf, buflen, _("Cannot resolve hostname(%s) %s"), hostname_str,
336                 myerrstr);
337       Dmsg1(20, "%s\n", buf);
338       return 0;
339    }
340
341    if (intype == IPADDR::R_SINGLE_PORT || intype == IPADDR::R_SINGLE_ADDR) {
342       IPADDR *addr;
343       if (addrs->size()) {
344          addr = (IPADDR *)addrs->first();
345       } else {
346          addr = New(IPADDR(family));
347          addr->set_type(type);
348          addr->set_port_net(defaultport);
349          addr->set_addr_any();
350          addrs->append(addr);
351       }
352       if (intype == IPADDR::R_SINGLE_PORT) {
353          addr->set_port_net(port);
354       }
355       if (intype == IPADDR::R_SINGLE_ADDR) {
356          addr->copy_addr((IPADDR *)(hostaddrs->first()));
357       }
358    } else {
359       foreach_dlist(iaddr, hostaddrs) {
360          IPADDR *clone;
361          /* for duplicates */
362          foreach_dlist(jaddr, addrs) {
363             if (iaddr->get_sockaddr_len() == jaddr->get_sockaddr_len() &&
364                 !memcmp(iaddr->get_sockaddr(), jaddr->get_sockaddr(),
365                     iaddr->get_sockaddr_len()))
366                 {
367                goto skip;          /* no price */
368             }
369          }
370          clone = New(IPADDR(*iaddr));
371          clone->set_type(type);
372          clone->set_port_net(port);
373          addrs->append(clone);
374        skip:
375          continue;
376       }
377    }
378    free_addresses(hostaddrs);
379    return 1;
380 }
381
382 /*
383  *  Some IPv6 rules from Wikipedia:
384  *
385  *  For convenience, an IPv6 address may be abbreviated to shorter
386  *  notations by application of the following rules, where possible.
387  *
388  * 1.  One or more leading zeroes from any groups of hexadecimal
389  *     digits are removed; this is usually done to either all or none of
390  *     the leading zeroes.  For example, the group 0042 is converted to
391  *     42.
392  *
393  * 2.  Consecutive sections of zeroes are replaced with a double
394  *     colon (::).  The double colon may only be used once in an
395  *     address, as multiple use would render the address indeterminate.
396  *     RFC 5952 recommends that a double colon must not be used to
397  *     denote an omitted single section of zeroes.[39]
398  *
399  *   my tests
400  *   positiv
401  *   = { ip = { addr = 1.2.3.4; port = 1205; } ipv4 = { addr = 1.2.3.4; port = http; } }
402  *   = { ip = {
403  *         addr = 1.2.3.4; port = 1205; }
404  *     ipv4 = {
405  *         addr = 1.2.3.4; port = http; }
406  *     ipv6 = {
407  *       addr = 1.2.3.4;
408  *       port = 1205;
409  *     }
410  *     ip = {
411  *       addr = 1.2.3.4
412  *       port = 1205
413  *     }
414  *     ip = {
415  *       addr = 1.2.3.4
416  *     }
417  *     ip = {
418  *       addr = 2001:220:222::2
419  *     }
420  *     ip = {
421  *       addr = bluedot.thun.net
422  *     }
423  *   }
424  *
425  *   negativ
426  *   = { ip = { } }
427  *   = { ipv4 { addr = doof.nowaytoheavenxyz.uhu; } }
428  *   = { ipv4 { port = 4711 } }
429  */
430 void store_addresses(LEX * lc, RES_ITEM * item, int index, int pass)
431 {
432    int token;
433    enum { EMPTYLINE = 0, PORTLINE = 0x1, ADDRLINE = 0x2 } next_line = EMPTYLINE;
434    int exist;
435    char hostname_str[1024];
436    char port_str[128];
437    int family = 0;
438    char errmsg[1024];
439
440
441    token = lex_get_token(lc, T_SKIP_EOL);
442    if (token != T_BOB) {
443       scan_err1(lc, _("Expected a block to begin with { but got: %s"), lc->str);
444    }
445
446    token = lex_get_token(lc, T_SKIP_EOL);
447    if (token == T_EOB) {
448       scan_err0(lc, _("Empty addr block is not allowed"));
449    }
450    do {
451       if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
452          scan_err1(lc, _("Expected a string but got: %s"), lc->str);
453       }
454       if (strcasecmp("ip", lc->str) == 0) {
455          family = AF_INET6;
456       } else if (strcasecmp("ipv4", lc->str) == 0) {
457          family = AF_INET;
458       }
459 #ifdef HAVE_IPV6
460       else if (strcasecmp("ipv6", lc->str) == 0) {
461          family = AF_INET6;
462       } else {
463          scan_err1(lc, _("Expected a string [ip|ipv4|ipv6] but got: %s"), lc->str);
464       }
465 #else
466       else {
467          scan_err1(lc, _("Expected a string [ip|ipv4] but got: %s"), lc->str);
468       }
469 #endif
470       token = lex_get_token(lc, T_SKIP_EOL);
471       if (token != T_EQUALS) {
472          scan_err1(lc, _("Expected an equal = but got: %s"), lc->str);
473       }
474       token = lex_get_token(lc, T_SKIP_EOL);
475       if (token != T_BOB) {
476          scan_err1(lc, _("Expected a block to begin with { but got: %s"), lc->str);
477       }
478       token = lex_get_token(lc, T_SKIP_EOL);
479       exist = EMPTYLINE;
480       port_str[0] = hostname_str[0] = '\0';
481       do {
482          if (token != T_IDENTIFIER) {
483             scan_err1(lc, _("Expected an identifier [addr|port] but got: %s"), lc->str);
484          }
485          if (strcasecmp("port", lc->str) == 0) {
486             next_line = PORTLINE;
487             if (exist & PORTLINE) {
488                scan_err0(lc, _("Only one port per address block"));
489             }
490             exist |= PORTLINE;
491          } else if (strcasecmp("addr", lc->str) == 0) {
492             next_line = ADDRLINE;
493             if (exist & ADDRLINE) {
494                scan_err0(lc, _("Only one addr per address block"));
495             }
496             exist |= ADDRLINE;
497          } else {
498             scan_err1(lc, _("Expected a identifier [addr|port] but got: %s"), lc->str);
499          }
500          token = lex_get_token(lc, T_SKIP_EOL);
501          if (token != T_EQUALS) {
502             scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
503          }
504          token = lex_get_token(lc, T_SKIP_EOL);
505          switch (next_line) {
506          case PORTLINE:
507             if (!
508                 (token == T_UNQUOTED_STRING || token == T_NUMBER ||
509                  token == T_IDENTIFIER)) {
510                scan_err1(lc, _("Expected a number or a string but got: %s"), lc->str);
511             }
512             bstrncpy(port_str, lc->str, sizeof(port_str));
513             break;
514          case ADDRLINE:
515             if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
516                scan_err1(lc, _("Expected an IP number or a hostname but got: %s"),
517                          lc->str);
518             }
519             bstrncpy(hostname_str, lc->str, sizeof(hostname_str));
520             break;
521          case EMPTYLINE:
522             scan_err0(lc, _("State machine missmatch"));
523             break;
524          }
525          token = lex_get_token(lc, T_SKIP_EOL);
526       } while (token == T_IDENTIFIER);
527       if (token != T_EOB) {
528          scan_err1(lc, _("Expected a end of block with } but got: %s"), lc->str);
529       }
530
531       if (pass == 1 && !add_address((dlist **)(item->value), IPADDR::R_MULTIPLE,
532                htons(item->default_value), family, hostname_str, port_str,
533                errmsg, sizeof(errmsg))) {
534          scan_err3(lc, _("Cannot add hostname(%s) and port(%s) to addrlist (%s)"),
535                    hostname_str, port_str, errmsg);
536       }
537       token = scan_to_next_not_eol(lc);
538    } while ((token == T_IDENTIFIER || token == T_UNQUOTED_STRING));
539    if (token != T_EOB) {
540       scan_err1(lc, _("Expected an end of block with } but got: %s"), lc->str);
541    }
542 }
543
544 void store_addresses_address(LEX * lc, RES_ITEM * item, int index, int pass)
545 {
546    char errmsg[1024];
547    int token = lex_get_token(lc, T_SKIP_EOL);
548    if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
549       scan_err1(lc, _("Expected an IP number or a hostname, got: %s"), lc->str);
550    }
551    if (pass == 1 && !add_address((dlist **)(item->value), IPADDR::R_SINGLE_ADDR,
552                     htons(item->default_value), AF_INET, lc->str, 0,
553                     errmsg, sizeof(errmsg))) {
554       scan_err2(lc, _("Cannot add port (%s) to (%s)"), lc->str, errmsg);
555    }
556 }
557
558 void store_addresses_port(LEX * lc, RES_ITEM * item, int index, int pass)
559 {
560    char errmsg[1024];
561    int token = lex_get_token(lc, T_SKIP_EOL);
562    if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
563       scan_err1(lc, _("Expected a port number or string, got: %s"), lc->str);
564    }
565    if (pass == 1 && !add_address((dlist **)(item->value), IPADDR::R_SINGLE_PORT,
566                     htons(item->default_value), AF_INET, 0, lc->str,
567                     errmsg, sizeof(errmsg))) {
568       scan_err2(lc, _("Cannot add port (%s) to (%s)"), lc->str, errmsg);
569    }
570 }
571
572 void free_addresses(dlist * addrs)
573 {
574    while (!addrs->empty()) {
575       IPADDR *ptr = (IPADDR*)addrs->first();
576       addrs->remove(ptr);
577       delete ptr;
578    }
579    delete addrs;
580 }
581
582 int sockaddr_get_port_net_order(const struct sockaddr *client_addr)
583 {
584    if (client_addr->sa_family == AF_INET) {
585       return ((struct sockaddr_in *)client_addr)->sin_port;
586    }
587 #ifdef HAVE_IPV6
588    else {
589       return ((struct sockaddr_in6 *)client_addr)->sin6_port;
590    }
591 #endif
592    return -1;
593 }
594
595 int sockaddr_get_port(const struct sockaddr *client_addr)
596 {
597    if (client_addr->sa_family == AF_INET) {
598       return ntohs(((struct sockaddr_in *)client_addr)->sin_port);
599    }
600 #ifdef HAVE_IPV6
601    else {
602       return ntohs(((struct sockaddr_in6 *)client_addr)->sin6_port);
603    }
604 #endif
605    return -1;
606 }
607
608
609 char *sockaddr_to_ascii(const struct sockaddr *sa, int socklen, char *buf, int buflen)
610 {
611 #ifdef HAVE_GETNAMEINFO
612   /* This is the more modern way of doing it */
613   char clienthost[NI_MAXHOST];
614   char clientservice[NI_MAXSERV];
615   int status = 1;
616   if (sa->sa_family == AF_INET) {
617      status = getnameinfo(sa, sizeof(sockaddr_in), clienthost, sizeof(clienthost),
618                  clientservice, sizeof(clientservice),
619                  NI_NUMERICHOST | NI_NUMERICSERV);
620   }
621 #ifdef HAVE_IPV6
622   else {
623      status = getnameinfo(sa, sizeof(sockaddr_in6), clienthost, sizeof(clienthost),
624                  clientservice, sizeof(clientservice),
625                  NI_NUMERICHOST | NI_NUMERICSERV);
626   }
627 #endif
628   if (status == 0) {
629      /* Enclose IPv6 in [] */
630      if (strchr(clienthost, ':') != NULL) {
631         bsnprintf(buf, buflen, "[%s]", clienthost);
632      } else {
633         bstrncpy(buf, clienthost, buflen);
634      }
635   } else {
636      bstrncpy(buf, "Hostname not found", buflen);
637   }
638
639 #else
640 #ifdef HAVE_INET_NTOP
641    inet_ntop(sa->sa_family,
642 # ifdef HAVE_IPV6
643              sa->sa_family == AF_INET ?
644                  (void*)&(((struct sockaddr_in*)sa)->sin_addr) :
645                  (void*)&(((struct sockaddr_in6*)sa)->sin6_addr),
646 # else
647                  (void*)&(((struct sockaddr_in*)sa)->sin_addr),
648 # endif /* HAVE_IPV6 */
649              buf, buflen);
650 #else
651    bstrncpy(buf, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), buflen);
652 #endif
653 #endif
654    return buf;
655 }
656
657 /*
658  * Remove duplicate IP addresses.
659  */
660 void remove_duplicate_addresses(dlist *addr_list)
661 {
662    IPADDR *ipaddr, *next, *duplicate;
663    /*
664     * Remove any duplicate addresses.
665     */
666    for (ipaddr = (IPADDR *)addr_list->first(); ipaddr;
667         ipaddr = (IPADDR *)addr_list->next(ipaddr)) {
668       for (next = (IPADDR *)addr_list->next(ipaddr); next; ) {
669          duplicate = NULL;
670          if (ipaddr->get_sockaddr_len() == next->get_sockaddr_len() &&
671              memcmp(ipaddr->get_sockaddr(), next->get_sockaddr(),
672                     ipaddr->get_sockaddr_len()) == 0) {
673             duplicate = next;
674          }
675          next = (IPADDR *)addr_list->next(next);
676          if (duplicate) {
677             addr_list->remove(duplicate);  /* remove from list */
678             delete duplicate;              /* free it */
679          }
680       }
681    }
682 }
683
684 #ifdef HAVE_OLD_SOCKOPT
685 int inet_aton(const char *cp, struct in_addr *inp)
686 {
687    struct in_addr inaddr;
688
689    if((inaddr.s_addr = inet_addr(cp)) != INADDR_NONE) {
690       inp->s_addr = inaddr.s_addr;
691       return 1;
692    }
693    return 0;
694 }
695 #endif