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