]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/address_conf.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / lib / address_conf.c
1 /*
2  *   Configuration file parser for IP-Addresse ipv4 and ipv6
3  *
4  *     Written by Meno Abels, June MMIIII
5  *
6  *     Version $Id$
7  */
8 /*
9    Copyright (C) 2004 Kern Sibbald and John Walker
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2 of
14    the License, or (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public
22    License along with this program; if not, write to the Free
23    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24    MA 02111-1307, USA.
25
26  */
27
28
29 #include "bacula.h"
30 #ifdef HAVE_ARPA_NAMESER_H
31 #include <arpa/nameser.h>
32 #endif
33 #ifdef HAVE_RESOLV_H
34 #include <resolv.h>
35 #endif
36
37 static int add_address(dlist **out, IPADDR::i_type type, unsigned short defaultport, int family,
38                 const char *hostname_str, const char *port_str, char **errstr);
39
40
41 IPADDR::IPADDR(const IPADDR &src) : type(src.type)
42 {
43   memcpy(&saddrbuf, &src.saddrbuf, sizeof(saddrbuf));
44   saddr  = &saddrbuf.dontuse;
45   saddr4 = &saddrbuf.dontuse4;
46 #ifdef HAVE_IPV6
47   saddr6 = &saddrbuf.dontuse6;
48 #endif
49 }
50
51 IPADDR::IPADDR(int af) : type(R_EMPTY)
52 {
53 #ifdef HAVE_IPV6
54   if (!(af  == AF_INET6 || af  == AF_INET)) {
55      Emsg1(M_ERROR_TERM, 0, _("Only ipv4 and ipv6 are supported (%d)\n"), af);
56   }
57 #else
58   if (af != AF_INET) {
59      Emsg1(M_ERROR_TERM, 0, _("Only ipv4 is supported (%d)\n"), af);
60   }
61 #endif
62   saddr  = &saddrbuf.dontuse;
63   saddr4 = &saddrbuf.dontuse4;
64 #ifdef HAVE_IPV6
65   saddr6 = &saddrbuf.dontuse6;
66 #endif
67   saddr->sa_family = af;
68   if (af  == AF_INET) {
69      saddr4->sin_port = 0xffff;
70   }
71 #ifdef HAVE_IPV6
72   else {
73      saddr6->sin6_port = 0xffff;
74   }
75 #endif
76 #ifdef HAVE_SA_LEN
77 #ifdef HAVE_IPV6
78   saddr->sa_len = (af == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
79 #else
80   saddr->sa_len = sizeof(sockaddr_in);
81 #endif
82 #endif
83    set_addr_any();
84 }
85
86 void IPADDR::set_type(i_type o)
87 {
88    type = o;
89 }
90
91 IPADDR::i_type IPADDR::get_type() const
92 {
93    return type;
94 }
95
96 unsigned short IPADDR::get_port_net_order() const
97 {
98    unsigned short port = 0;
99    if (saddr->sa_family == AF_INET) {
100       port = saddr4->sin_port;
101    }
102 #ifdef HAVE_IPV6
103    else {
104       port = saddr6->sin6_port;
105    }
106 #endif
107     return port;
108 }
109
110 void IPADDR::set_port_net(unsigned short port)
111 {
112    if (saddr->sa_family == AF_INET) {
113       saddr4->sin_port = port;
114    }
115 #ifdef HAVE_IPV6
116    else {
117       saddr6->sin6_port = port;
118    }
119 #endif
120 }
121
122 int IPADDR::get_family() const
123 {
124     return saddr->sa_family;
125 }
126
127 struct sockaddr *IPADDR::get_sockaddr()
128 {
129    return saddr;
130 }
131
132 int IPADDR::get_sockaddr_len()
133 {
134 #ifdef HAVE_IPV6
135    return saddr->sa_family == AF_INET ? sizeof(*saddr4) : sizeof(*saddr6);
136 #else
137    return sizeof(*saddr4);
138 #endif
139 }
140 void IPADDR::copy_addr(IPADDR *src)
141 {
142    if (saddr->sa_family == AF_INET) {
143       saddr4->sin_addr.s_addr = src->saddr4->sin_addr.s_addr;
144    }
145 #ifdef HAVE_IPV6
146    else {
147       saddr6->sin6_addr = src->saddr6->sin6_addr;
148    }
149 #endif
150 }
151
152 void IPADDR::set_addr_any()
153 {
154    if (saddr->sa_family == AF_INET) {
155       saddr4->sin_addr.s_addr = INADDR_ANY;
156    }
157 #ifdef HAVE_IPV6
158    else {
159      saddr6->sin6_addr= in6addr_any;
160    }
161 #endif
162 }
163
164 void IPADDR::set_addr4(struct in_addr *ip4)
165 {
166    if (saddr->sa_family != AF_INET) {
167       Emsg1(M_ERROR_TERM, 0, _("It was tried to assign a ipv6 address to a ipv4(%d)\n"), saddr->sa_family);
168    }
169    saddr4->sin_addr = *ip4;
170 }
171
172 #ifdef HAVE_IPV6
173 void IPADDR::set_addr6(struct in6_addr *ip6)
174 {
175    if (saddr->sa_family != AF_INET6) {
176       Emsg1(M_ERROR_TERM, 0, _("It was tried to assign a ipv4 address to a ipv6(%d)\n"), saddr->sa_family);
177    }
178    saddr6->sin6_addr = *ip6;
179 }
180 #endif
181
182 const char *IPADDR::get_address(char *outputbuf, int outlen)
183 {
184    outputbuf[0] = '\0';
185 #ifdef HAVE_INET_NTOP
186 # ifdef HAVE_IPV6
187    inet_ntop(saddr->sa_family, saddr->sa_family == AF_INET ?
188               (void*)&(saddr4->sin_addr) : (void*)&(saddr6->sin6_addr),
189               outputbuf, outlen);
190 # else
191    inet_ntop(saddr->sa_family, (void*)&(saddr4->sin_addr), outputbuf, outlen);
192 # endif
193 #else
194    bstrncpy(outputbuf, inet_ntoa(saddr4->sin_addr), outlen);
195 #endif
196    return outputbuf;
197 }
198
199 const char *IPADDR::build_address_str(char *buf, int blen)
200 {
201    char tmp[1024];
202    bsnprintf(buf, blen, "host[%s:%s:%hu] ",
203             get_family() == AF_INET ? "ipv4" : "ipv6",
204             get_address(tmp, sizeof(tmp) - 1), get_port_host_order());
205    return buf;
206 }
207
208 const char *build_addresses_str(dlist *addrs, char *buf, int blen)
209 {
210    if (!addrs || addrs->size() == 0) {
211       bstrncpy(buf, "", blen);
212       return buf;
213    }
214    char *work = buf;
215    IPADDR *p;
216    foreach_dlist(p, addrs) {
217       char tmp[1024];
218       int len = bsnprintf(work, blen, "%s", p->build_address_str(tmp, sizeof(tmp)));
219       if (len < 0)
220          break;
221       work += len;
222       blen -= len;
223    }
224    return buf;
225 }
226
227 const char *get_first_address(dlist * addrs, char *outputbuf, int outlen)
228 {
229    return ((IPADDR *)(addrs->first()))->get_address(outputbuf, outlen);
230 }
231
232 int get_first_port_net_order(dlist * addrs)
233 {
234    if (!addrs) {
235       return 0;
236    } else {
237       return ((IPADDR *)(addrs->first()))->get_port_net_order();
238    }
239 }
240
241 int get_first_port_host_order(dlist * addrs)
242 {
243    if (!addrs) {
244       return 0;
245    } else {
246       return ((IPADDR *)(addrs->first()))->get_port_host_order();
247    }
248 }
249
250 void init_default_addresses(dlist **out, int port)
251 {
252    char *errstr;
253    unsigned short sport = port;
254    if (!add_address(out, IPADDR::R_DEFAULT, htons(sport), AF_INET, 0, 0, &errstr)) {
255       Emsg1(M_ERROR_TERM, 0, _("Can't add default address (%s)\n"), errstr);
256       free(errstr);
257    }
258 }
259
260 static int add_address(dlist **out, IPADDR::i_type type, unsigned short defaultport, int family,
261                 const char *hostname_str, const char *port_str, char **errstr)
262 {
263    IPADDR *iaddr;
264    IPADDR *jaddr;
265    dlist *hostaddrs;
266    unsigned short port;
267    IPADDR::i_type intype = type;
268
269    dlist *addrs = (dlist *)(*(out));
270    if (!addrs) {
271       IPADDR *tmp = 0;
272       addrs = *out = New(dlist(tmp, &tmp->link));
273    }
274
275    type = (type == IPADDR::R_SINGLE_PORT
276            || type == IPADDR::R_SINGLE_ADDR) ? IPADDR::R_SINGLE : type;
277    if (type != IPADDR::R_DEFAULT) {
278       IPADDR *def = 0;
279       foreach_dlist(iaddr, addrs) {
280          if (iaddr->get_type() == IPADDR::R_DEFAULT) {
281             def = iaddr;
282          } else if (iaddr->get_type() != type) {
283             *errstr = (char *)malloc(1024);
284             bsnprintf(*errstr, 1023,
285                       "the old style addresses cannot be mixed with new style");
286             return 0;
287          }
288       }
289       if (def) {
290          addrs->remove(def);
291          delete def;
292       }
293    }
294
295
296    if (!port_str || port_str[0] == '\0') {
297       port = defaultport;
298    } else {
299       int pnum = atol(port_str);
300       if (0 < pnum && pnum < 0xffff) {
301          port = htons(pnum);
302       } else {
303          struct servent *s = getservbyname(port_str, "tcp");
304          if (s) {
305             port = s->s_port;
306          } else {
307             *errstr = (char *)malloc(1024);
308             bsnprintf(*errstr, 1023, "can't resolve service(%s)", port_str);
309             return 0;
310          }
311       }
312    }
313
314    const char *myerrstr;
315    hostaddrs = bnet_host2ipaddrs(hostname_str, family, &myerrstr);
316    if (!hostaddrs) {
317       *errstr = (char *)malloc(1024);
318       bsnprintf(*errstr, 1023, "can't resolve hostname(%s) %s", hostname_str,
319                 myerrstr);
320       return 0;
321    }
322
323    if (intype == IPADDR::R_SINGLE_PORT || intype == IPADDR::R_SINGLE_ADDR) {
324       IPADDR *addr;
325       if (addrs->size()) {
326          addr = (IPADDR *)addrs->first();
327       } else {
328          addr = New(IPADDR(family));
329          addr->set_type(type);
330          addr->set_port_net(defaultport);
331          addr->set_addr_any();
332          addrs->append(addr);
333       }
334       if (intype == IPADDR::R_SINGLE_PORT) {
335          addr->set_port_net(port);
336       }
337       if (intype == IPADDR::R_SINGLE_ADDR) {
338          addr->copy_addr((IPADDR *) (hostaddrs->first()));
339       }
340    } else {
341       foreach_dlist(iaddr, hostaddrs) {
342          IPADDR *clone;
343          /* for duplicates */
344          foreach_dlist(jaddr, addrs) {
345             if (iaddr->get_sockaddr_len() == jaddr->get_sockaddr_len() &&
346             !memcmp(iaddr->get_sockaddr(), jaddr->get_sockaddr(),
347                     iaddr->get_sockaddr_len()))
348                 {
349                goto skip;          /* no price */
350             }
351          }
352          clone = New(IPADDR(*iaddr));
353          clone->set_type(type);
354          clone->set_port_net(port);
355          addrs->append(clone);
356        skip:
357          continue;
358       }
359    }
360    free_addresses(hostaddrs);
361    return 1;
362 }
363
364 /*
365  *   my tests
366  *   positiv
367  *   = { ip = { addr = 1.2.3.4; port = 1205; } ipv4 = { addr = 1.2.3.4; port = http; } }
368  *   = { ip = {
369  *         addr = 1.2.3.4; port = 1205; }
370  *     ipv4 = {
371  *         addr = 1.2.3.4; port = http; }
372  *     ipv6 = {
373  *       addr = 1.2.3.4;
374  *       port = 1205;
375  *     }
376  *     ip = {
377  *       addr = 1.2.3.4
378  *       port = 1205
379  *     }
380  *     ip = {
381  *       addr = 1.2.3.4
382  *     }
383  *     ip = {
384  *       addr = 2001:220:222::2
385  *     }
386  *     ip = {
387  *       addr = bluedot.thun.net
388  (     }
389  *   }
390  *   negativ
391  *   = { ip = { } }
392  *   = { ipv4 { addr = doof.nowaytoheavenxyz.uhu; } }
393  *   = { ipv4 { port = 4711 } }
394  */
395 void store_addresses(LEX * lc, RES_ITEM * item, int index, int pass)
396 {
397    int token;
398    enum { EMPTYLINE = 0, PORTLINE = 0x1, ADDRLINE = 0x2 } next_line = EMPTYLINE;
399    int exist;
400    char hostname_str[1024];
401    char port_str[128];
402    int family = 0;
403
404
405    token = lex_get_token(lc, T_SKIP_EOL);
406    if (token != T_BOB) {
407       scan_err1(lc, _("Expected a block begin { , got: %s"), lc->str);
408    }
409
410    token = lex_get_token(lc, T_SKIP_EOL);
411    if (token == T_EOB) {
412       scan_err0(lc, _("Empty addr block is not allowed"));
413    }
414    do {
415       if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
416          scan_err1(lc, _("Expected a string, got: %s"), lc->str);
417       }
418       if (strcasecmp("ip", lc->str) == 0 || strcasecmp("ipv4", lc->str) == 0) {
419          family = AF_INET;
420       }
421 #ifdef HAVE_IPV6
422       else if (strcasecmp("ipv6", lc->str) == 0) {
423          family = AF_INET6;
424       } else {
425          scan_err1(lc, _("Expected a string [ip|ipv4|ipv6], got: %s"), lc->str);
426       }
427 #else
428       else {
429          scan_err1(lc, _("Expected a string [ip|ipv4], got: %s"), lc->str);
430       }
431 #endif
432       token = lex_get_token(lc, T_SKIP_EOL);
433       if (token != T_EQUALS) {
434          scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
435       }
436       token = lex_get_token(lc, T_SKIP_EOL);
437       if (token != T_BOB) {
438          scan_err1(lc, _("Expected a block beginn { , got: %s"), lc->str);
439       }
440       token = lex_get_token(lc, T_SKIP_EOL);
441       exist = EMPTYLINE;
442       port_str[0] = hostname_str[0] = '\0';
443       do {
444          if (token != T_IDENTIFIER) {
445             scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
446          }
447          if (strcasecmp("port", lc->str) == 0) {
448             next_line = PORTLINE;
449             if (exist & PORTLINE) {
450                scan_err0(lc, _("Only one port per address block"));
451             }
452             exist |= PORTLINE;
453          } else if (strcasecmp("addr", lc->str) == 0) {
454             next_line = ADDRLINE;
455             if (exist & ADDRLINE) {
456                scan_err0(lc, _("Only one addr per address block"));
457             }
458             exist |= ADDRLINE;
459          } else {
460             scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
461          }
462          token = lex_get_token(lc, T_SKIP_EOL);
463          if (token != T_EQUALS) {
464             scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
465          }
466          token = lex_get_token(lc, T_SKIP_EOL);
467          switch (next_line) {
468          case PORTLINE:
469             if (!
470                 (token == T_UNQUOTED_STRING || token == T_NUMBER
471                  || token == T_IDENTIFIER)) {
472                scan_err1(lc, _("Expected a number or a string, got: %s"), lc->str);
473             }
474             bstrncpy(port_str, lc->str, sizeof(port_str));
475             break;
476          case ADDRLINE:
477             if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
478                scan_err1(lc, _("Expected an IP number or a hostname, got: %s"),
479                          lc->str);
480             }
481             bstrncpy(hostname_str, lc->str, sizeof(hostname_str));
482             break;
483          case EMPTYLINE:
484             scan_err0(lc, _("State machine missmatch"));
485             break;
486          }
487          token = lex_get_token(lc, T_SKIP_EOL);
488       } while (token == T_IDENTIFIER);
489       if (token != T_EOB) {
490          scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
491       }
492
493       char *errstr;
494       if (pass == 1 && !add_address((dlist **)(item->value), IPADDR::R_MULTIPLE,
495                htons(item->default_value), family, hostname_str, port_str, &errstr)) {
496            scan_err3(lc, _("Can't add hostname(%s) and port(%s) to addrlist (%s)"),
497                    hostname_str, port_str, errstr);
498            free(errstr);
499         }
500       token = scan_to_next_not_eol(lc);
501    } while ((token == T_IDENTIFIER || token == T_UNQUOTED_STRING));
502    if (token != T_EOB) {
503       scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
504    }
505 }
506
507 void store_addresses_address(LEX * lc, RES_ITEM * item, int index, int pass)
508 {
509
510    int token = lex_get_token(lc, T_SKIP_EOL);
511    if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
512       scan_err1(lc, _("Expected a hostname or IP nummer, got: %s"), lc->str);
513    }
514    char *errstr;
515    if (pass == 1 && !add_address((dlist **) (item->value), IPADDR::R_SINGLE_ADDR,
516                     htons(item->default_value), AF_INET, lc->str, 0, &errstr)) {
517       scan_err2(lc, _("can't add port (%s) to (%s)"), lc->str, errstr);
518       free(errstr);
519    }
520 }
521
522 void store_addresses_port(LEX * lc, RES_ITEM * item, int index, int pass)
523 {
524    int token = lex_get_token(lc, T_SKIP_EOL);
525    if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
526       scan_err1(lc, _("Expected a port number or string, got: %s"), lc->str);
527    }
528    char *errstr;
529    if (pass == 1 && !add_address((dlist **)(item->value), IPADDR::R_SINGLE_PORT,
530                     htons(item->default_value), AF_INET, 0, lc->str, &errstr)) {
531       scan_err2(lc, _("can't add port (%s) to (%s)"), lc->str, errstr);
532       free(errstr);
533    }
534 }
535
536 void free_addresses(dlist * addrs)
537 {
538    while (!addrs->empty()) {
539       IPADDR *ptr = (IPADDR*)addrs->first();
540       addrs->remove(ptr);
541       delete ptr;
542    }
543    delete addrs;
544 }
545
546 int sockaddr_get_port_net_order(const struct sockaddr *client_addr)
547 {
548    if (client_addr->sa_family == AF_INET) {
549       return ((struct sockaddr_in *)client_addr)->sin_port;
550    }
551 #ifdef HAVE_IPV6
552    else {
553       return ((struct sockaddr_in6 *)client_addr)->sin6_port;
554    }
555 #endif
556    return -1;
557 }
558
559 int sockaddr_get_port(const struct sockaddr *client_addr)
560 {
561    if (client_addr->sa_family == AF_INET) {
562       return ntohs(((struct sockaddr_in *)client_addr)->sin_port);
563    }
564 #ifdef HAVE_IPV6
565    else {
566       return ntohs(((struct sockaddr_in6 *)client_addr)->sin6_port);
567    }
568 #endif
569    return -1;
570 }
571
572
573 char *sockaddr_to_ascii(const struct sockaddr *sa, char *buf, int len)
574 {
575 #ifdef HAVE_INET_NTOP
576    /* MA Bug 5 the problem was that i mixed up sockaddr and in_addr */
577    inet_ntop(sa->sa_family,
578 # ifdef HAVE_IPV6
579              sa->sa_family == AF_INET ? 
580                  (void*)&(((struct sockaddr_in*)sa)->sin_addr) :
581                  (void*)&(((struct sockaddr_in6*)sa)->sin6_addr),
582 # else
583                  (void*)&(((struct sockaddr_in*)sa)->sin_addr),
584 # endif /* HAVE_IPV6 */
585              buf, len);
586 #else
587    bstrncpy(buf, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), len);
588 #endif
589    return buf;
590 }
591
592 #ifdef HAVE_OLD_SOCKOPT
593 int inet_aton(const char *cp, struct in_addr *inp)
594 {
595    struct in_addr inaddr;
596
597    if((inaddr.s_addr = inet_addr(cp)) != INADDR_NONE) {
598       inp->s_addr = inaddr.s_addr;
599       return 1;
600    }
601    return 0;
602 }
603 #endif