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