1 /* strongSwan IPsec config file parser
2 * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include "../pluto/constants.h"
25 #include "../pluto/defs.h"
26 #include "../pluto/log.h"
32 #include "interfaces.h"
34 /* strings containing a colon are interpreted as an IPv6 address */
35 #define ip_version(string) (strchr(string, ':') != NULL)? AF_INET6 : AF_INET;
37 static const char ike_defaults
[] = "aes128-sha-modp2048";
38 static const char esp_defaults
[] = "aes128-sha1, 3des-md5";
40 static const char firewall_defaults
[] = "ipsec _updown iptables";
42 static void default_values(starter_config_t
*cfg
)
47 memset(cfg
, 0, sizeof(struct starter_config
));
49 /* is there enough space for all seen flags? */
50 assert(KW_SETUP_LAST
- KW_SETUP_FIRST
<
51 sizeof(cfg
->setup
.seen
) * BITS_PER_BYTE
);
52 assert(KW_CONN_LAST
- KW_CONN_FIRST
<
53 sizeof(cfg
->conn_default
.seen
) * BITS_PER_BYTE
);
54 assert(KW_END_LAST
- KW_END_FIRST
<
55 sizeof(cfg
->conn_default
.right
.seen
) * BITS_PER_BYTE
);
56 assert(KW_CA_LAST
- KW_CA_FIRST
<
57 sizeof(cfg
->ca_default
.seen
) * BITS_PER_BYTE
);
59 cfg
->setup
.seen
= LEMPTY
;
60 cfg
->setup
.fragicmp
= TRUE
;
61 cfg
->setup
.hidetos
= TRUE
;
62 cfg
->setup
.uniqueids
= TRUE
;
63 cfg
->setup
.interfaces
= new_list("%defaultroute");
64 cfg
->setup
.charonstart
= TRUE
;
65 cfg
->setup
.plutostart
= TRUE
;
67 cfg
->conn_default
.seen
= LEMPTY
;
68 cfg
->conn_default
.startup
= STARTUP_NO
;
69 cfg
->conn_default
.state
= STATE_IGNORE
;
70 cfg
->conn_default
.policy
= POLICY_ENCRYPT
| POLICY_TUNNEL
| POLICY_RSASIG
|
71 POLICY_PFS
| POLICY_MOBIKE
;
73 cfg
->conn_default
.ike
= clone_str(ike_defaults
, "ike_defaults");
74 cfg
->conn_default
.esp
= clone_str(esp_defaults
, "esp_defaults");
75 cfg
->conn_default
.sa_ike_life_seconds
= OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT
;
76 cfg
->conn_default
.sa_ipsec_life_seconds
= PLUTO_SA_LIFE_DURATION_DEFAULT
;
77 cfg
->conn_default
.sa_rekey_margin
= SA_REPLACEMENT_MARGIN_DEFAULT
;
78 cfg
->conn_default
.sa_rekey_fuzz
= SA_REPLACEMENT_FUZZ_DEFAULT
;
79 cfg
->conn_default
.sa_keying_tries
= SA_REPLACEMENT_RETRIES_DEFAULT
;
80 cfg
->conn_default
.addr_family
= AF_INET
;
81 cfg
->conn_default
.tunnel_addr_family
= AF_INET
;
83 cfg
->conn_default
.left
.seen
= LEMPTY
;
84 cfg
->conn_default
.right
.seen
= LEMPTY
;
86 cfg
->conn_default
.left
.sendcert
= CERT_SEND_IF_ASKED
;
87 cfg
->conn_default
.right
.sendcert
= CERT_SEND_IF_ASKED
;
89 anyaddr(AF_INET
, &cfg
->conn_default
.left
.addr
);
90 anyaddr(AF_INET
, &cfg
->conn_default
.left
.nexthop
);
91 anyaddr(AF_INET
, &cfg
->conn_default
.left
.srcip
);
92 anyaddr(AF_INET
, &cfg
->conn_default
.right
.addr
);
93 anyaddr(AF_INET
, &cfg
->conn_default
.right
.nexthop
);
94 anyaddr(AF_INET
, &cfg
->conn_default
.right
.srcip
);
96 cfg
->ca_default
.seen
= LEMPTY
;
99 #define KW_POLICY_FLAG(sy, sn, fl) \
100 if (streq(kw->value, sy)) { conn->policy |= fl; } \
101 else if (streq(kw->value, sn)) { conn->policy &= ~fl; } \
102 else { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); cfg->err++; }
105 load_setup(starter_config_t
*cfg
, config_parsed_t
*cfgp
)
110 DBG_log("Loading config setup")
113 for (kw
= cfgp
->config_setup
; kw
; kw
= kw
->next
)
115 bool assigned
= FALSE
;
117 kw_token_t token
= kw
->entry
->token
;
119 if (token
< KW_SETUP_FIRST
|| token
> KW_SETUP_LAST
)
121 plog("# unsupported keyword '%s' in config setup", kw
->entry
->name
);
126 if (!assign_arg(token
, KW_SETUP_FIRST
, kw
, (char *)cfg
, &assigned
))
128 plog(" bad argument value in config setup");
136 kw_end(starter_conn_t
*conn
, starter_end_t
*end
, kw_token_t token
137 , kw_list_t
*kw
, char *conn_name
, starter_config_t
*cfg
)
140 bool assigned
= FALSE
;
141 int has_port_wildcard
; /* set if port is %any */
143 char *name
= kw
->entry
->name
;
144 char *value
= kw
->value
;
146 if (!assign_arg(token
, KW_END_FIRST
, kw
, (char *)end
, &assigned
))
149 if (token
== KW_SENDCERT
)
151 if (end
->sendcert
== CERT_YES_SEND
)
152 end
->sendcert
= CERT_ALWAYS_SEND
;
153 else if (end
->sendcert
== CERT_NO_SEND
)
154 end
->sendcert
= CERT_NEVER_SEND
;
163 if (streq(value
, "%defaultroute"))
165 if (cfg
->defaultroute
.defined
)
167 end
->addr
= cfg
->defaultroute
.addr
;
168 end
->nexthop
= cfg
->defaultroute
.nexthop
;
172 plog("# default route not known: %s=%s", name
, value
);
176 else if (streq(value
, "%any"))
178 anyaddr(conn
->addr_family
, &end
->addr
);
180 else if (streq(value
, "%any6"))
182 conn
->addr_family
= AF_INET6
;
183 anyaddr(conn
->addr_family
, &end
->addr
);
185 else if (streq(value
, "%group"))
189 conn
->policy
|= POLICY_GROUP
| POLICY_TUNNEL
;
190 anyaddr(conn
->addr_family
, &end
->addr
);
191 anyaddr(conn
->tunnel_addr_family
, &any
);
192 initsubnet(&any
, 0, '0', &end
->subnet
);
193 end
->has_client
= TRUE
;
197 /* check for allow_any prefix */
200 end
->allow_any
= TRUE
;
203 conn
->addr_family
= ip_version(value
);
204 ugh
= ttoaddr(value
, 0, conn
->addr_family
, &end
->addr
);
207 plog("# bad addr: %s=%s [%s]", name
, value
, ugh
);
208 if (streq(ugh
, "does not look numeric and name lookup failed"))
210 end
->dns_failed
= TRUE
;
211 anyaddr(conn
->addr_family
, &end
->addr
);
221 if (streq(value
, "%defaultroute"))
223 if (cfg
->defaultroute
.defined
)
224 end
->nexthop
= cfg
->defaultroute
.nexthop
;
227 plog("# default route not known: %s=%s", name
, value
);
231 else if (streq(value
, "%direct"))
233 ugh
= anyaddr(conn
->addr_family
, &end
->nexthop
);
237 conn
->addr_family
= ip_version(value
);
238 ugh
= ttoaddr(value
, 0, conn
->addr_family
, &end
->nexthop
);
242 plog("# bad addr: %s=%s [%s]", name
, value
, ugh
);
247 if ((strlen(value
) >= 6 && strncmp(value
,"vhost:",6) == 0)
248 || (strlen(value
) >= 5 && strncmp(value
,"vnet:",5) == 0))
250 end
->virt
= clone_str(value
, "virt");
254 end
->has_client
= TRUE
;
255 conn
->tunnel_addr_family
= ip_version(value
);
256 ugh
= ttosubnet(value
, 0, conn
->tunnel_addr_family
, &end
->subnet
);
259 plog("# bad subnet: %s=%s [%s]", name
, value
, ugh
);
264 case KW_SUBNETWITHIN
:
265 end
->has_client
= TRUE
;
266 end
->has_client_wildcard
= TRUE
;
267 conn
->tunnel_addr_family
= ip_version(value
);
268 ugh
= ttosubnet(value
, 0, conn
->tunnel_addr_family
, &end
->subnet
);
271 ugh
= ttoprotoport(value
, 0, &end
->protocol
, &end
->port
, &has_port_wildcard
);
272 end
->has_port_wildcard
= has_port_wildcard
;
277 plog("# natip and sourceip cannot be defined at the same time");
280 if (streq(value
, "%modeconfig") || streq(value
, "%modecfg") ||
281 streq(value
, "%config") || streq(value
, "%cfg"))
287 conn
->tunnel_addr_family
= ip_version(value
);
288 ugh
= ttoaddr(value
, 0, conn
->tunnel_addr_family
, &end
->srcip
);
291 plog("# bad addr: %s=%s [%s]", name
, value
, ugh
);
294 end
->has_srcip
= TRUE
;
296 conn
->policy
|= POLICY_TUNNEL
;
301 plog("# natip and sourceip cannot be defined at the same time");
304 if (streq(value
, "%defaultroute"))
306 if (cfg
->defaultroute
.defined
)
308 end
->srcip
= cfg
->defaultroute
.addr
;
312 plog("# default route not known: %s=%s", name
, value
);
318 conn
->tunnel_addr_family
= ip_version(value
);
319 ugh
= ttoaddr(value
, 0, conn
->tunnel_addr_family
, &end
->srcip
);
322 plog("# bad addr: %s=%s [%s]", name
, value
, ugh
);
326 end
->has_natip
= TRUE
;
327 conn
->policy
|= POLICY_TUNNEL
;
335 plog(" bad argument value in conn '%s'", conn_name
);
340 * handles left|right=<FQDN> DNS resolution failure
343 handle_dns_failure( const char *label
, starter_end_t
*end
, starter_config_t
*cfg
)
349 plog("# fallback to %s=%%any due to '%%' prefix or %sallowany=yes",
354 /* declare an error */
361 * handles left|rightfirewall and left|rightupdown parameters
364 handle_firewall( const char *label
, starter_end_t
*end
, starter_config_t
*cfg
)
366 if (end
->firewall
&& (end
->seen
& LELEM(KW_FIREWALL
- KW_END_FIRST
)))
368 if (end
->updown
!= NULL
)
370 plog("# cannot have both %sfirewall and %supdown", label
, label
);
375 end
->updown
= clone_str(firewall_defaults
, "firewall_defaults");
376 end
->firewall
= FALSE
;
382 * parse a conn section
385 load_conn(starter_conn_t
*conn
, kw_list_t
*kw
, starter_config_t
*cfg
)
387 char *conn_name
= (conn
->name
== NULL
)?
"%default":conn
->name
;
389 for ( ; kw
; kw
= kw
->next
)
391 bool assigned
= FALSE
;
393 kw_token_t token
= kw
->entry
->token
;
395 if (token
>= KW_LEFT_FIRST
&& token
<= KW_LEFT_LAST
)
397 kw_end(conn
, &conn
->left
, token
- KW_LEFT_FIRST
+ KW_END_FIRST
398 , kw
, conn_name
, cfg
);
401 else if (token
>= KW_RIGHT_FIRST
&& token
<= KW_RIGHT_LAST
)
403 kw_end(conn
, &conn
->right
, token
- KW_RIGHT_FIRST
+ KW_END_FIRST
404 , kw
, conn_name
, cfg
);
408 if (token
== KW_AUTO
)
410 token
= KW_CONN_SETUP
;
412 else if (token
== KW_ALSO
)
416 also_t
*also
= alloc_thing(also_t
, "also_t");
418 also
->name
= clone_str(kw
->value
, "also");
419 also
->next
= conn
->also
;
423 DBG_log(" also=%s", kw
->value
)
429 if (token
< KW_CONN_FIRST
|| token
> KW_CONN_LAST
)
431 plog("# unsupported keyword '%s' in conn '%s'"
432 , kw
->entry
->name
, conn_name
);
437 if (!assign_arg(token
, KW_CONN_FIRST
, kw
, (char *)conn
, &assigned
))
439 plog(" bad argument value in conn '%s'", conn_name
);
450 conn
->policy
&= ~(POLICY_TUNNEL
| POLICY_SHUNT_MASK
);
451 if (streq(kw
->value
, "tunnel"))
452 conn
->policy
|= POLICY_TUNNEL
;
453 else if (streq(kw
->value
, "beet"))
454 conn
->policy
|= POLICY_BEET
;
455 else if (streq(kw
->value
, "passthrough") || streq(kw
->value
, "pass"))
456 conn
->policy
|= POLICY_SHUNT_PASS
;
457 else if (streq(kw
->value
, "drop"))
458 conn
->policy
|= POLICY_SHUNT_DROP
;
459 else if (streq(kw
->value
, "reject"))
460 conn
->policy
|= POLICY_SHUNT_REJECT
;
461 else if (strcmp(kw
->value
, "transport") != 0)
463 plog("# bad policy value: %s=%s", kw
->entry
->name
, kw
->value
);
468 KW_POLICY_FLAG("yes", "no", POLICY_PFS
)
471 KW_POLICY_FLAG("yes", "no", POLICY_COMPRESS
)
474 KW_POLICY_FLAG("ah", "esp", POLICY_AUTHENTICATE
)
477 conn
->policy
&= ~(POLICY_ID_AUTH_MASK
| POLICY_ENCRYPT
);
479 if (!(streq(kw
->value
, "never") || streq(kw
->value
, "eap")))
481 char *value
= kw
->value
;
482 char *second
= strchr(kw
->value
, '|');
487 /* also handles the cases secret|rsasig and rsasig|secret */
490 if (streq(value
, "rsasig"))
491 conn
->policy
|= POLICY_RSASIG
| POLICY_ENCRYPT
;
492 else if (streq(value
, "secret") || streq(value
, "psk"))
493 conn
->policy
|= POLICY_PSK
| POLICY_ENCRYPT
;
494 else if (streq(value
, "xauthrsasig"))
495 conn
->policy
|= POLICY_XAUTH_RSASIG
| POLICY_ENCRYPT
;
496 else if (streq(value
, "xauthpsk"))
497 conn
->policy
|= POLICY_XAUTH_PSK
| POLICY_ENCRYPT
;
500 plog("# bad policy value: %s=%s", kw
->entry
->name
, kw
->value
);
507 second
= NULL
; /* traverse the loop no more than twice */
512 /* TODO: a gperf function for all EAP types */
513 if (streq(kw
->value
, "aka"))
517 else if (streq(kw
->value
, "sim"))
521 else if (streq(kw
->value
, "md5"))
527 conn
->eap
= atoi(kw
->value
);
530 plog("# unknown EAP type: %s=%s", kw
->entry
->name
, kw
->value
);
536 if (streq(kw
->value
, "%forever"))
538 conn
->sa_keying_tries
= 0;
544 conn
->sa_keying_tries
= strtoul(kw
->value
, &endptr
, 10);
547 plog("# bad integer value: %s=%s", kw
->entry
->name
, kw
->value
);
553 KW_POLICY_FLAG("no", "yes", POLICY_DONT_REKEY
)
556 KW_POLICY_FLAG("no", "yes", POLICY_DONT_REAUTH
)
559 KW_POLICY_FLAG("yes", "no", POLICY_MOBIKE
)
562 KW_POLICY_FLAG("yes", "no", POLICY_FORCE_ENCAP
)
565 KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH
)
568 KW_POLICY_FLAG("server", "client", POLICY_XAUTH_SERVER
)
575 handle_dns_failure("left", &conn
->left
, cfg
);
576 handle_dns_failure("right", &conn
->right
, cfg
);
577 handle_firewall("left", &conn
->left
, cfg
);
578 handle_firewall("right", &conn
->right
, cfg
);
582 * initialize a conn object with the default conn
585 conn_default(char *name
, starter_conn_t
*conn
, starter_conn_t
*def
)
587 memcpy(conn
, def
, sizeof(starter_conn_t
));
588 conn
->name
= clone_str(name
, "conn name");
590 clone_args(KW_CONN_FIRST
, KW_CONN_LAST
, (char *)conn
, (char *)def
);
591 clone_args(KW_END_FIRST
, KW_END_LAST
, (char *)&conn
->left
, (char *)&def
->left
);
592 clone_args(KW_END_FIRST
, KW_END_LAST
, (char *)&conn
->right
, (char *)&def
->right
);
599 load_ca(starter_ca_t
*ca
, kw_list_t
*kw
, starter_config_t
*cfg
)
601 char *ca_name
= (ca
->name
== NULL
)?
"%default":ca
->name
;
603 for ( ; kw
; kw
= kw
->next
)
605 bool assigned
= FALSE
;
607 kw_token_t token
= kw
->entry
->token
;
609 if (token
== KW_AUTO
)
613 else if (token
== KW_ALSO
)
617 also_t
*also
= alloc_thing(also_t
, "also_t");
619 also
->name
= clone_str(kw
->value
, "also");
620 also
->next
= ca
->also
;
624 DBG_log(" also=%s", kw
->value
)
630 if (token
< KW_CA_FIRST
|| token
> KW_CA_LAST
)
632 plog("# unsupported keyword '%s' in ca '%s'", kw
->entry
->name
, ca_name
);
637 if (!assign_arg(token
, KW_CA_FIRST
, kw
, (char *)ca
, &assigned
))
639 plog(" bad argument value in ca '%s'", ca_name
);
644 /* treat 'route' and 'start' as 'add' */
645 if (ca
->startup
!= STARTUP_NO
)
646 ca
->startup
= STARTUP_ADD
;
650 * initialize a ca object with the default ca
653 ca_default(char *name
, starter_ca_t
*ca
, starter_ca_t
*def
)
655 memcpy(ca
, def
, sizeof(starter_ca_t
));
656 ca
->name
= clone_str(name
, "ca name");
658 clone_args(KW_CA_FIRST
, KW_CA_LAST
, (char *)ca
, (char *)def
);
662 find_also_conn(const char* name
, starter_conn_t
*conn
, starter_config_t
*cfg
);
665 load_also_conns(starter_conn_t
*conn
, also_t
*also
, starter_config_t
*cfg
)
669 kw_list_t
*kw
= find_also_conn(also
->name
, conn
, cfg
);
673 plog(" conn '%s' cannot include '%s'", conn
->name
, also
->name
);
678 DBG_log("conn '%s' includes '%s'", conn
->name
, also
->name
)
680 /* only load if no error occurred in the first round */
682 load_conn(conn
, kw
, cfg
);
689 * find a conn included by also
692 find_also_conn(const char* name
, starter_conn_t
*conn
, starter_config_t
*cfg
)
694 starter_conn_t
*c
= cfg
->conn_first
;
698 if (streq(name
, c
->name
))
700 if (conn
->visit
== c
->visit
)
702 plog("# detected also loop");
706 c
->visit
= conn
->visit
;
707 load_also_conns(conn
, c
->also
, cfg
);
713 plog("# also '%s' not found", name
);
719 find_also_ca(const char* name
, starter_ca_t
*ca
, starter_config_t
*cfg
);
722 load_also_cas(starter_ca_t
*ca
, also_t
*also
, starter_config_t
*cfg
)
726 kw_list_t
*kw
= find_also_ca(also
->name
, ca
, cfg
);
730 plog(" ca '%s' cannot include '%s'", ca
->name
, also
->name
);
735 DBG_log("ca '%s' includes '%s'", ca
->name
, also
->name
)
737 /* only load if no error occurred in the first round */
739 load_ca(ca
, kw
, cfg
);
746 * find a ca included by also
749 find_also_ca(const char* name
, starter_ca_t
*ca
, starter_config_t
*cfg
)
751 starter_ca_t
*c
= cfg
->ca_first
;
755 if (streq(name
, c
->name
))
757 if (ca
->visit
== c
->visit
)
759 plog("# detected also loop");
763 c
->visit
= ca
->visit
;
764 load_also_cas(ca
, c
->also
, cfg
);
770 plog("# also '%s' not found", name
);
776 * free the memory used by also_t objects
779 free_also(also_t
*head
)
792 * free the memory used by a starter_conn_t object
795 confread_free_conn(starter_conn_t
*conn
)
797 free_args(KW_END_FIRST
, KW_END_LAST
, (char *)&conn
->left
);
798 free_args(KW_END_FIRST
, KW_END_LAST
, (char *)&conn
->right
);
799 free_args(KW_CONN_NAME
, KW_CONN_LAST
, (char *)conn
);
800 free_also(conn
->also
);
804 * free the memory used by a starter_ca_t object
807 confread_free_ca(starter_ca_t
*ca
)
809 free_args(KW_CA_NAME
, KW_CA_LAST
, (char *)ca
);
814 * free the memory used by a starter_config_t object
817 confread_free(starter_config_t
*cfg
)
819 starter_conn_t
*conn
= cfg
->conn_first
;
820 starter_ca_t
*ca
= cfg
->ca_first
;
822 free_args(KW_SETUP_FIRST
, KW_SETUP_LAST
, (char *)cfg
);
824 confread_free_conn(&cfg
->conn_default
);
828 starter_conn_t
*conn_aux
= conn
;
831 confread_free_conn(conn_aux
);
835 confread_free_ca(&cfg
->ca_default
);
839 starter_ca_t
*ca_aux
= ca
;
842 confread_free_ca(ca_aux
);
850 * load and parse an IPsec configuration file
853 confread_load(const char *file
)
855 starter_config_t
*cfg
= NULL
;
856 config_parsed_t
*cfgp
;
857 section_list_t
*sconn
, *sca
;
858 starter_conn_t
*conn
;
864 /* load IPSec configuration file */
865 cfgp
= parser_load_conf(file
);
869 cfg
= (starter_config_t
*)alloc_thing(starter_config_t
, "starter_config_t");
871 /* set default values */
874 /* determine default route */
875 get_defaultroute(&cfg
->defaultroute
);
877 /* load config setup section */
878 load_setup(cfg
, cfgp
);
880 /* in the first round parse also statements */
881 cfg
->parse_also
= TRUE
;
883 /* find %default ca section */
884 for (sca
= cfgp
->ca_first
; sca
; sca
= sca
->next
)
886 if (streq(sca
->name
, "%default"))
889 DBG_log("Loading ca %%default")
891 load_ca(&cfg
->ca_default
, sca
->kw
, cfg
);
895 /* parameters defined in ca %default sections can be overloads */
896 cfg
->ca_default
.seen
= LEMPTY
;
898 /* load other ca sections */
899 for (sca
= cfgp
->ca_first
; sca
; sca
= sca
->next
)
903 /* skip %default ca section */
904 if (streq(sca
->name
, "%default"))
908 DBG_log("Loading ca '%s'", sca
->name
)
910 ca
= (starter_ca_t
*)alloc_thing(starter_ca_t
, "starter_ca_t");
912 ca_default(sca
->name
, ca
, &cfg
->ca_default
);
916 previous_err
= cfg
->err
;
917 load_ca(ca
, ca
->kw
, cfg
);
918 if (cfg
->err
> previous_err
)
920 /* errors occurred - free the ca */
921 confread_free_ca(ca
);
922 cfg
->non_fatal_err
+= cfg
->err
- previous_err
;
923 cfg
->err
= previous_err
;
927 /* success - insert the ca into the chained list */
929 cfg
->ca_last
->next
= ca
;
936 for (ca
= cfg
->ca_first
; ca
; ca
= ca
->next
)
938 also_t
*also
= ca
->also
;
942 kw_list_t
*kw
= find_also_ca(also
->name
, cfg
->ca_first
, cfg
);
944 load_ca(ca
, kw
, cfg
);
948 if (ca
->startup
!= STARTUP_NO
)
949 ca
->state
= STATE_TO_ADD
;
952 /* find %default conn sections */
953 for (sconn
= cfgp
->conn_first
; sconn
; sconn
= sconn
->next
)
955 if (streq(sconn
->name
, "%default"))
958 DBG_log("Loading conn %%default")
960 load_conn(&cfg
->conn_default
, sconn
->kw
, cfg
);
964 /* parameter defined in conn %default sections can be overloaded */
965 cfg
->conn_default
.seen
= LEMPTY
;
966 cfg
->conn_default
.right
.seen
= LEMPTY
;
967 cfg
->conn_default
.left
.seen
= LEMPTY
;
969 /* load other conn sections */
970 for (sconn
= cfgp
->conn_first
; sconn
; sconn
= sconn
->next
)
974 /* skip %default conn section */
975 if (streq(sconn
->name
, "%default"))
979 DBG_log("Loading conn '%s'", sconn
->name
)
981 conn
= (starter_conn_t
*)alloc_thing(starter_conn_t
, "starter_conn_t");
983 conn_default(sconn
->name
, conn
, &cfg
->conn_default
);
984 conn
->kw
= sconn
->kw
;
987 previous_err
= cfg
->err
;
988 load_conn(conn
, conn
->kw
, cfg
);
989 if (cfg
->err
> previous_err
)
991 /* error occurred - free the conn */
992 confread_free_conn(conn
);
993 cfg
->non_fatal_err
+= cfg
->err
- previous_err
;
994 cfg
->err
= previous_err
;
998 /* success - insert the conn into the chained list */
1000 cfg
->conn_last
->next
= conn
;
1001 cfg
->conn_last
= conn
;
1002 if (!cfg
->conn_first
)
1003 cfg
->conn_first
= conn
;
1007 /* in the second round do not parse also statements */
1008 cfg
->parse_also
= FALSE
;
1010 for (ca
= cfg
->ca_first
; ca
; ca
= ca
->next
)
1012 ca
->visit
= ++visit
;
1013 load_also_cas(ca
, ca
->also
, cfg
);
1015 if (ca
->startup
!= STARTUP_NO
)
1016 ca
->state
= STATE_TO_ADD
;
1019 for (conn
= cfg
->conn_first
; conn
; conn
= conn
->next
)
1021 conn
->visit
= ++visit
;
1022 load_also_conns(conn
, conn
->also
, cfg
);
1024 if (conn
->startup
!= STARTUP_NO
)
1025 conn
->state
= STATE_TO_ADD
;
1028 parser_free_conf(cfgp
);
1030 total_err
= cfg
->err
+ cfg
->non_fatal_err
;
1033 plog("### %d parsing error%s (%d fatal) ###"
1034 , total_err
, (total_err
> 1)?
"s":"", cfg
->err
);