]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/address_conf.c
Implement user friendly time duration input editing
[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
31 IPADDR::IPADDR(const IPADDR &src) : type(src.type)
32 {
33   memcpy(&buf, &src.buf, sizeof(buf));
34   saddr  = &buf.dontuse;
35   saddr4 = &buf.dontuse4; 
36 #ifdef HAVE_IPV6
37   saddr6 = &buf.dontuse6;
38 #endif
39 }
40
41 IPADDR::IPADDR(int af) : type(R_EMPTY)
42 {
43   if (!(af  == AF_INET6 || af  == AF_INET)) {
44      Emsg1(M_ERROR_TERM, 0, _("Only ipv4 and ipv6 are supported(%d)\n"), af);
45   }
46   saddr  = &buf.dontuse;
47   saddr4 = &buf.dontuse4; 
48 #ifdef HAVE_IPV6
49   saddr6 = &buf.dontuse6;
50 #endif
51   saddr->sa_family = af;
52   if (af  == AF_INET) {
53      saddr4->sin_port = 0xffff;
54   }
55 #ifdef HAVE_IPV6
56   else {
57      saddr6->sin6_port = 0xffff;
58   }
59 #endif
60 #ifdef HAVE_SA_LEN
61 #ifdef HAVE_IPV6
62   saddr->sa_len = (af == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
63 #else
64   saddr->sa_len = sizeof(sockaddr_in);
65 #endif
66 #endif
67    set_addr_any(); 
68
69
70 void IPADDR::set_type(i_type o)
71 {
72    type = o;
73 }
74
75 IPADDR::i_type IPADDR::get_type() const
76 {
77    return type;
78 }
79
80 unsigned short IPADDR::get_port() const
81 {
82    unsigned short port = 0;
83    if (saddr->sa_family == AF_INET) {
84       port = saddr4->sin_port;
85    }
86 #ifdef HAVE_IPV6
87    else {
88       port = saddr6->sin6_port;
89    }
90 #endif
91     return port;
92 }
93
94 void IPADDR::set_port(unsigned short port)
95 {
96    if (saddr->sa_family == AF_INET) {
97       saddr4->sin_port = port;
98    }
99 #ifdef HAVE_IPV6
100    else {
101       saddr6->sin6_port = port;
102    }
103 #endif
104 }
105
106 int IPADDR::get_family() const
107 {
108     return saddr->sa_family;
109 }       
110
111 struct sockaddr *IPADDR::get_sockaddr()
112 {
113    return saddr;
114 }
115
116 int IPADDR::get_sockaddr_len()
117 {
118 #ifdef HAVE_IPV6
119    return saddr->sa_family == AF_INET ? sizeof(*saddr4) : sizeof(*saddr6);
120 #else
121    return sizeof(*saddr4);
122 #endif
123 }
124 void IPADDR::copy_addr(IPADDR *src)
125 {
126    if (saddr->sa_family == AF_INET) {
127       saddr4->sin_addr.s_addr = src->saddr4->sin_addr.s_addr;
128    }
129 #ifdef HAVE_IPV6
130    else {
131       saddr6->sin6_addr = src->saddr6->sin6_addr;
132    }
133 #endif
134
135
136 void IPADDR::set_addr_any()
137 {
138    if (saddr->sa_family == AF_INET) {
139       saddr4->sin_addr.s_addr = INADDR_ANY;
140    }
141 #ifdef HAVE_IPV6
142    else {
143      saddr6->sin6_addr= in6addr_any;
144    }
145 #endif
146 }
147
148 void IPADDR::set_addr4(struct in_addr *ip4)
149
150    if (saddr->sa_family != AF_INET) {
151       Emsg1(M_ERROR_TERM, 0, _("It was tried to assign a ipv6 address to a ipv4(%d)\n"), saddr->sa_family);
152    }
153    saddr4->sin_addr = *ip4;
154 }
155
156 #ifdef HAVE_IPV6
157 void IPADDR::set_addr6(struct in6_addr *ip6)
158
159    if (saddr->sa_family != AF_INET6) {
160       Emsg1(M_ERROR_TERM, 0, _("It was tried to assign a ipv4 address to a ipv6(%d)\n"), saddr->sa_family);
161    }
162    saddr6->sin6_addr = *ip6;
163 }
164 #endif
165
166 const char *IPADDR::get_address(char *outputbuf, int outlen)
167 {
168    outputbuf[0] = '\0';
169 #if defined(HAVE_INET_NTOP) && defined(HAVE_IPV6)
170    inet_ntop(saddr->sa_family, saddr->sa_family == AF_INET ?
171               (void*)&(saddr4->sin_addr) : (void*)&(saddr6->sin6_addr),
172               outputbuf, outlen);
173 #else
174    bstrncpy(outputbuf, inet_ntoa(saddr4->sin_addr), outlen);
175 #endif
176    return outputbuf;
177 }
178
179 const char *IPADDR::build_address_str(char *buf, int blen) 
180 {
181    char tmp[1024];
182    snprintf(buf, blen, "host[%s:%s:%hu] ",
183             get_family() == AF_INET ? "ipv4" : "ipv6",
184             get_address(tmp, sizeof(tmp) - 1), ntohs(get_port()));
185    return buf;
186 }
187
188 const char *build_addresses_str(dlist *addrs, char *buf, int blen) 
189 {
190    if (!addrs->size()) {
191       bstrncpy(buf, "", blen);
192       return buf;
193    }
194    char *work = buf;
195    IPADDR *p;
196    foreach_dlist(p, addrs) {
197       char tmp[1024];
198       int len = snprintf(work, blen, "%s", p->build_address_str(tmp, sizeof(tmp)));
199       if (len < 0)
200          break;
201       work += len;
202       blen -= len;
203    }
204    return buf;
205 }
206
207 const char *get_first_address(dlist * addrs, char *outputbuf, int outlen)
208 {
209    return ((IPADDR *)(addrs->first()))->get_address(outputbuf, outlen);
210 }
211
212 int get_first_port(dlist * addrs)
213 {
214    return ((IPADDR *)(addrs->first()))->get_port();
215 }
216
217 static int skip_to_next_not_eol(LEX * lc)
218 {
219    int token;
220
221    do {
222       token = lex_get_token(lc, T_ALL);
223    } while (token == T_EOL);
224    return token;
225 }
226
227
228 void init_default_addresses(dlist ** out, int port)
229 {
230    char *errstr;
231    unsigned short sport = port;
232    if (!add_address(out, IPADDR::R_DEFAULT, htons(sport), AF_INET, 0, 0, &errstr)) {
233       Emsg1(M_ERROR_TERM, 0, _("Can't add default address (%s)\n"), errstr);
234       free(errstr);
235    }
236 }
237
238 int add_address(dlist ** out, IPADDR::i_type type, unsigned short defaultport, int family,
239                 const char *hostname_str, const char *port_str, char **errstr)
240 {
241    IPADDR *iaddr;
242    IPADDR *jaddr;
243    dlist *hostaddrs;
244    unsigned short port;
245    IPADDR::i_type intype = type;
246
247    dlist *addrs = (dlist *) (*(out));
248    if (!addrs) {
249       IPADDR *tmp = 0;
250       addrs = *out = new dlist(tmp, &tmp->link);
251    }
252
253    type = (type == IPADDR::R_SINGLE_PORT
254            || type == IPADDR::R_SINGLE_ADDR) ? IPADDR::R_SINGLE : type;
255    if (type != IPADDR::R_DEFAULT) {
256       IPADDR *def = 0;
257       foreach_dlist(iaddr, addrs) {
258          if (iaddr->get_type() == IPADDR::R_DEFAULT) {
259             def = iaddr;
260          } else if (iaddr->get_type() != type) {
261             *errstr = (char *)malloc(1024);
262             bsnprintf(*errstr, 1023,
263                       "the old style addresses could mixed with new style");
264             return 0;
265          }
266       }
267       if (def) {
268          addrs->remove(def);
269          delete def;
270       }
271    }
272
273
274    if (!port_str || port_str[0] == '\0') {
275       port = defaultport;
276    } else {
277       int pnum = atol(port_str);
278       if (0 < pnum && pnum < 0xffff) {
279          port = htons(pnum);
280       } else {
281          struct servent *s = getservbyname(port_str, "tcp");
282          if (s) {
283             port = s->s_port;
284          } else {
285             *errstr = (char *)malloc(1024);
286             bsnprintf(*errstr, 1023, "can't resolve service(%s)", port_str);
287             return 0;
288          }
289       }
290    }
291
292    const char *myerrstr;
293    hostaddrs = bnet_host2ipaddrs(hostname_str, family, &myerrstr);
294    if (!hostaddrs) {
295       *errstr = (char *)malloc(1024);
296       bsnprintf(*errstr, 1023, "can't resolve hostname(%s) %s", hostname_str,
297                 myerrstr);
298       return 0;
299    }
300
301    if (intype == IPADDR::R_SINGLE_PORT || intype == IPADDR::R_SINGLE_ADDR) {
302       IPADDR *addr;
303       if (addrs->size()) {
304          addr = (IPADDR *) addrs->first();
305       } else {
306          addr = new IPADDR(family);
307          addr->set_type(type);
308          addr->set_port(defaultport);
309          addr->set_addr_any();
310          addrs->append(addr);
311       }
312       if (intype == IPADDR::R_SINGLE_PORT) {
313          addr->set_port(port);
314       }
315       if (intype == IPADDR::R_SINGLE_ADDR) {
316          addr->copy_addr((IPADDR *) (hostaddrs->first()));
317       }
318    } else {
319       foreach_dlist(iaddr, hostaddrs) {
320          IPADDR *clone;
321          /* for duplicates */
322          foreach_dlist(jaddr, addrs) {
323             if (iaddr->get_sockaddr_len() == jaddr->get_sockaddr_len() &&
324             !memcmp(iaddr->get_sockaddr(), jaddr->get_sockaddr(), 
325                     iaddr->get_sockaddr_len()))
326                 {
327                goto skip;          /* no price */
328             }
329          }
330          clone = new IPADDR(*iaddr);
331          clone->set_type(type);
332          clone->set_port(port);
333          addrs->append(clone);
334        skip:
335          continue;
336       }
337    }
338    free_addresses(hostaddrs);
339    return 1;
340 }
341
342 void store_addresses(LEX * lc, RES_ITEM * item, int index, int pass)
343 {
344    int token;
345    enum { EMPTYLINE = 0, PORTLINE = 0x1, ADDRLINE = 0x2 } next_line = EMPTYLINE;
346    int exist;
347    char hostname_str[1024];
348    char port_str[128];
349    int family = 0;
350
351    /*
352     *   =  { [[ip|ipv4|ipv6] = { [[addr|port] = [^ ]+[\n;]+] }]+ }
353     *   or my tests
354     *   positiv
355     *   = { ip = { addr = 1.2.3.4; port = 1205; } ipv4 = { addr = 1.2.3.4; port = http; } }
356     *   = { ip = { 
357     *         addr = 1.2.3.4; port = 1205; } 
358     *     ipv4 = { 
359     *         addr = 1.2.3.4; port = http; } 
360     *     ipv6 = { 
361     *       addr = 1.2.3.4; 
362     *       port = 1205;
363     *     } 
364     *     ip = {
365     *       addr = 1.2.3.4
366     *       port = 1205
367     *     } 
368     *     ip = {
369     *       addr = 1.2.3.4
370     *     } 
371     *     ip = {
372     *       addr = 2001:220:222::2
373     *     } 
374     *     ip = {
375     *       addr = bluedot.thun.net
376     (     } 
377     *   }
378     *   negativ
379     *   = { ip = { } }
380     *   = { ipv4 { addr = doof.nowaytoheavenxyz.uhu; } }
381     *   = { ipv4 { port = 4711 } }
382     */
383
384    token = skip_to_next_not_eol(lc);
385    if (token != T_BOB) {
386       scan_err1(lc, _("Expected a block begin { , got: %s"), lc->str);
387    }
388
389    token = skip_to_next_not_eol(lc);
390    if (token == T_EOB) {
391       scan_err0(lc, _("Empty addr block is not allowed"));
392    }
393    do {
394       if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
395          scan_err1(lc, _("Expected a string, got: %s"), lc->str);
396       }
397       if (!strcmp("ip", lc->str) || !strcmp("ipv4", lc->str)) {
398          family = AF_INET;
399       }
400 #ifdef HAVE_IPV6
401       else if (!strcmp("ipv6", lc->str)) {
402          family = AF_INET6;
403       }
404 #endif
405       else {
406          scan_err1(lc, _("Expected a string [ip|ipv4|ipv6], got: %s"), lc->str);
407       }
408       token = skip_to_next_not_eol(lc);
409       if (token != T_EQUALS) {
410          scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
411       }
412       token = skip_to_next_not_eol(lc);
413       if (token != T_BOB) {
414          scan_err1(lc, _("Expected a block beginn { , got: %s"), lc->str);
415       }
416       token = skip_to_next_not_eol(lc);
417       exist = EMPTYLINE;
418       port_str[0] = hostname_str[0] = '\0';
419       do {
420          if (token != T_IDENTIFIER) {
421             scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
422          }
423          if (!strcmp("port", lc->str)) {
424             next_line = PORTLINE;
425             if (exist & PORTLINE) {
426                scan_err0(lc, _("Only one port per address block"));
427             }
428             exist |= PORTLINE;
429          } else if (!strcmp("addr", lc->str)) {
430             next_line = ADDRLINE;
431             if (exist & ADDRLINE) {
432                scan_err0(lc, _("Only one addr per address block"));
433             }
434             exist |= ADDRLINE;
435          } else {
436             scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
437          }
438          token = lex_get_token(lc, T_ALL);
439          if (token != T_EQUALS) {
440             scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
441          }
442          token = lex_get_token(lc, T_ALL);
443          switch (next_line) {
444          case PORTLINE:
445             if (!
446                 (token == T_UNQUOTED_STRING || token == T_NUMBER
447                  || token == T_IDENTIFIER)) {
448                scan_err1(lc, _("Expected a number or a string, got: %s"), lc->str);
449             }
450             bstrncpy(port_str, lc->str, sizeof(port_str));
451             break;
452          case ADDRLINE:
453             if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
454                scan_err1(lc, _("Expected a ipnumber or a hostname, got: %s"),
455                          lc->str);
456             }
457             bstrncpy(hostname_str, lc->str, sizeof(hostname_str));
458             break;
459          case EMPTYLINE:
460             scan_err0(lc, _("Statemachine missmatch"));
461             break;
462          }
463          token = skip_to_next_not_eol(lc);
464       } while (token == T_IDENTIFIER);
465       if (token != T_EOB) {
466          scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
467       }
468
469       char *errstr;
470       if (!add_address
471           ((dlist **) (item->value), IPADDR::R_MULTIPLE, htons(item->default_value),
472            family, hostname_str, port_str, &errstr)) {
473          scan_err3(lc, _("Can't add hostname(%s) and port(%s) to addrlist (%s)"),
474                    hostname_str, port_str, errstr);
475          free(errstr);
476       }
477       token = skip_to_next_not_eol(lc);
478    } while ((token == T_IDENTIFIER || token == T_UNQUOTED_STRING));
479    if (token != T_EOB) {
480       scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
481    }
482 }
483
484 void store_addresses_address(LEX * lc, RES_ITEM * item, int index, int pass)
485 {
486    int token = lex_get_token(lc, T_ALL);
487    if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
488       scan_err1(lc, _("Expected a hostname or ipnummer, got: %s"), lc->str);
489    }
490    char *errstr;
491    if (!add_address((dlist **) (item->value), IPADDR::R_SINGLE_ADDR,
492                     htons(item->default_value), AF_INET, lc->str, 0, &errstr)) {
493       scan_err2(lc, _("can't add port (%s) to (%s)"), lc->str, errstr);
494       free(errstr);
495    }
496 }
497
498 void store_addresses_port(LEX * lc, RES_ITEM * item, int index, int pass)
499 {
500    int token = lex_get_token(lc, T_ALL);
501    if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
502       scan_err1(lc, _("Expected a port nummer or string, got: %s"), lc->str);
503    }
504    char *errstr;
505    if (!add_address((dlist **) (item->value), IPADDR::R_SINGLE_PORT,
506                     htons(item->default_value), AF_INET, 0, lc->str, &errstr)) {
507       scan_err2(lc, _("can't add port (%s) to (%s)"), lc->str, errstr);
508       free(errstr);
509    }
510 }
511
512 void free_addresses(dlist * addrs)
513 {
514    while (!addrs->empty()) {
515       IPADDR *ptr = (IPADDR*)addrs->first();
516       addrs->remove(ptr);
517       delete ptr;
518    }
519    delete addrs;
520 }
521
522