bud_error_t bud_config_init(bud_config_t* config) { bud_error_t err; int i; int r; /* Get addresses of frontend and backend */ r = bud_config_str_to_addr(config->frontend.host, config->frontend.port, &config->frontend.addr); if (r != 0) return bud_error_num(kBudErrPton, r); for (i = 0; i < config->frontend.interface.count; i++) { bud_config_addr_t* addr; addr = &config->frontend.interface.list[i]; r = bud_config_str_to_addr(addr->host, addr->port, &addr->addr); if (r != 0) return bud_error_num(kBudErrPton, r); } err = bud_config_format_proxyline(config); if (!bud_is_ok(err)) return err; i = 0; config->balance_e = bud_config_balance_to_enum(config->balance); /* At least one backend should be present for non-SNI balancing */ if (config->contexts[0].backend.count == 0 && config->balance_e != kBudBalanceSNI) { err = bud_error(kBudErrNoBackend); goto fatal; } /* Get indexes for SSL_set_ex_data()/SSL_get_ex_data() */ if (kBudSSLClientIndex == -1) { kBudSSLConfigIndex = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); kBudSSLClientIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); kBudSSLSNIIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); kBudSSLTicketKeyIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (kBudSSLConfigIndex == -1 || kBudSSLClientIndex == -1 || kBudSSLSNIIndex == -1 || kBudSSLTicketKeyIndex == -1) { err = bud_error(kBudErrNoSSLIndex); goto fatal; } } #ifndef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB if (config->context_count != 0) { err = bud_error(kBudErrSNINotSupported); goto fatal; } #endif /* !SSL_CTRL_SET_TLSEXT_SERVERNAME_CB */ /* Allocate workers */ if (!config->is_worker && config->worker_count != 0) { config->workers = calloc(config->worker_count, sizeof(*config->workers)); if (config->workers == NULL) { err = bud_error_str(kBudErrNoMem, "workers"); goto fatal; } } /* Initialize logger */ config->logger = bud_logger_new(config, &err); if (!bud_is_ok(err)) goto fatal; err = bud_config_init_tracing(&config->trace); if (!bud_is_ok(err)) goto fatal; if (config->is_worker || config->worker_count == 0) { /* Connect to SNI server */ if (config->sni.enabled) { config->sni.pool = bud_http_pool_new(config, config->sni.host, config->sni.port, &err); if (config->sni.pool == NULL) goto fatal; } /* Connect to OCSP Stapling server */ if (config->stapling.enabled) { config->stapling.pool = bud_http_pool_new(config, config->stapling.host, config->stapling.port, &err); if (config->stapling.pool == NULL) goto fatal; } } /* Init all contexts */ for (i = 0; i < config->context_count + 1; i++) { err = bud_context_init(config, &config->contexts[i]); if (!bud_is_ok(err)) goto fatal; } return bud_ok(); fatal: /* Free all allocated contexts */ do bud_context_free(&config->contexts[i--]); while (i >= 0); return err; }
bud_error_t bud_sni_from_json(bud_config_t* config, struct json_value_t* json, bud_context_t* ctx) { JSON_Object* obj; JSON_Value* val; const char* cert_str; const char* key_str; const char* pass_str; JSON_Array* cert_strs; JSON_Array* key_strs; JSON_Array* pass_strs; bud_error_t err; cert_str = NULL; key_str = NULL; pass_str = NULL; cert_strs = NULL; key_strs = NULL; pass_strs = NULL; obj = json_value_get_object(json); val = json_object_get_value(obj, "cert"); if (json_value_get_type(val) == JSONString) cert_str = json_value_get_string(val); else cert_strs = json_value_get_array(val); val = json_object_get_value(obj, "key"); if (json_value_get_type(val) == JSONString) key_str = json_value_get_string(val); else key_strs = json_value_get_array(val); val = json_object_get_value(obj, "passphrase"); if (json_value_get_type(val) == JSONString) pass_str = json_value_get_string(val); else pass_strs = json_value_get_array(val); if (obj == NULL || !((cert_str != NULL && key_str != NULL) || (cert_strs != NULL && key_strs != NULL))) { err = bud_error_str(kBudErrJSONParse, "<SNI Response>"); goto fatal; } /* Load NPN from response */ memset(ctx, 0, sizeof(*ctx)); ctx->cert_file = cert_str; ctx->key_file = key_str; ctx->key_pass = pass_str; ctx->cert_files = cert_strs; ctx->key_files = key_strs; ctx->key_passes = pass_strs; ctx->ciphers = json_object_get_string(obj, "ciphers"); ctx->ecdh = json_object_get_string(obj, "ecdh"); ctx->ticket_key = json_object_get_string(obj, "ticket_key"); ctx->npn = json_object_get_array(obj, "npn"); ctx->ca_array = json_object_get_array(obj, "ca"); val = json_object_get_value(obj, "request_cert"); if (val != NULL) ctx->request_cert = json_value_get_boolean(val); err = bud_config_load_backend_list(config, obj, &ctx->backend); if (!bud_is_ok(err)) goto fatal; err = bud_context_init(config, ctx); /* Make sure that deallocated values won't be used */ ctx->cert_file = NULL; ctx->key_file = NULL; ctx->key_pass = NULL; ctx->cert_files = NULL; ctx->key_files = NULL; ctx->key_passes = NULL; if (!bud_is_ok(err)) goto fatal; return bud_ok(); fatal: if (!bud_is_ok(err)) { SSL_CTX_free(ctx->ctx); ctx->ctx = NULL; } free(ctx->backend.list); ctx->backend.list = NULL; return err; }