aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar David Garcia Quintas <dgq@google.com>2017-02-07 13:26:41 -0800
committerGravatar David Garcia Quintas <dgq@google.com>2017-02-07 17:41:57 -0800
commit012915045fca08c365add95a8e29eb40021ecd64 (patch)
tree875ceda9ff8d9b5330e6aa2acc85b1017d9b4886 /src
parent547974e47857e2b5099a4d16b17f271a4cb88ca1 (diff)
Secure naming support for gRPCLB
Diffstat (limited to 'src')
-rw-r--r--src/core/ext/client_channel/subchannel.c16
-rw-r--r--src/core/ext/client_channel/subchannel.h3
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c171
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb_channel.c77
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb_channel.h56
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c107
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c7
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.c171
-rw-r--r--src/core/lib/iomgr/sockaddr_utils.c38
-rw-r--r--src/core/lib/iomgr/sockaddr_utils.h4
-rw-r--r--src/core/lib/security/credentials/credentials.c47
-rw-r--r--src/core/lib/security/credentials/credentials.h13
-rw-r--r--src/core/lib/security/credentials/fake/fake_credentials.c8
-rw-r--r--src/core/lib/security/credentials/fake/fake_credentials.h15
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c2
-rw-r--r--src/core/lib/security/transport/lb_targets_info.c70
-rw-r--r--src/core/lib/security/transport/lb_targets_info.h47
-rw-r--r--src/core/lib/security/transport/security_connector.c141
-rw-r--r--src/core/lib/security/transport/security_connector.h7
-rw-r--r--src/core/lib/security/transport/security_handshaker.c4
-rw-r--r--src/core/lib/surface/init_secure.c2
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py2
22 files changed, 846 insertions, 162 deletions
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index f1e4e079e2..abbbfdfd64 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -788,7 +788,8 @@ grpc_call_stack *grpc_subchannel_call_get_call_stack(
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
}
-static void grpc_uri_to_sockaddr(char *uri_str, grpc_resolved_address *addr) {
+static void grpc_uri_to_sockaddr(const char *uri_str,
+ grpc_resolved_address *addr) {
grpc_uri *uri = grpc_uri_parse(uri_str, 0 /* suppress_errors */);
GPR_ASSERT(uri != NULL);
if (strcmp(uri->scheme, "ipv4") == 0) {
@@ -803,14 +804,19 @@ static void grpc_uri_to_sockaddr(char *uri_str, grpc_resolved_address *addr) {
void grpc_get_subchannel_address_arg(const grpc_channel_args *args,
grpc_resolved_address *addr) {
+ const char *addr_uri_str = grpc_get_subchannel_address_uri_arg(args);
+ memset(addr, 0, sizeof(*addr));
+ if (*addr_uri_str != '\0') {
+ grpc_uri_to_sockaddr(addr_uri_str, addr);
+ }
+}
+
+const char *grpc_get_subchannel_address_uri_arg(const grpc_channel_args *args) {
const grpc_arg *addr_arg =
grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_ADDRESS);
GPR_ASSERT(addr_arg != NULL); // Should have been set by LB policy.
GPR_ASSERT(addr_arg->type == GRPC_ARG_STRING);
- memset(addr, 0, sizeof(*addr));
- if (*addr_arg->value.string != '\0') {
- grpc_uri_to_sockaddr(addr_arg->value.string, addr);
- }
+ return addr_arg->value.string;
}
grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr) {
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h
index 9bd35a7704..26ce954487 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/client_channel/subchannel.h
@@ -178,6 +178,9 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
void grpc_get_subchannel_address_arg(const grpc_channel_args *args,
grpc_resolved_address *addr);
+/// Returns the URI string for the address to connect to.
+const char *grpc_get_subchannel_address_uri_arg(const grpc_channel_args *args);
+
/// Returns a new channel arg encoding the subchannel address as a string.
/// Caller is responsible for freeing the string.
grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address *addr);
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index 308facb7e7..ab62e5ed6a 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -112,11 +112,13 @@
#include "src/core/ext/client_channel/lb_policy_registry.h"
#include "src/core/ext/client_channel/parse_address.h"
#include "src/core/ext/lb_policy/grpclb/grpclb.h"
+#include "src/core/ext/lb_policy/grpclb/grpclb_channel.h"
#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/slice/slice_hash_table.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/backoff.h"
@@ -751,6 +753,96 @@ static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_ERROR_UNREF(error);
}
+static void destroy_balancer_name(grpc_exec_ctx *exec_ctx,
+ void *balancer_name) {
+ gpr_free(balancer_name);
+}
+
+static void *copy_balancer_name(void *balancer_name) {
+ return gpr_strdup(balancer_name);
+}
+
+static grpc_slice_hash_table_entry targets_info_entry_create(
+ const char *address, const char *balancer_name) {
+ static const grpc_slice_hash_table_vtable vtable = {destroy_balancer_name,
+ copy_balancer_name};
+ grpc_slice_hash_table_entry entry;
+ entry.key = grpc_slice_from_copied_string(address);
+ entry.value = (void *)balancer_name;
+ entry.vtable = &vtable;
+ return entry;
+}
+
+/* Returns the target URI for the LB service whose addresses are in \a
+ * addresses. Using this URI, a bidirectional streaming channel will be created
+ * for the reception of load balancing updates.
+ *
+ * The output argument \a targets_info will be updated to contain a mapping of
+ * "LB server address" to "balancer name", as reported by the naming system.
+ * This mapping will be propagated via the channel arguments of the
+ * aforementioned LB streaming channel, to be used by the security connector for
+ * secure naming checks. The user is responsible for freeing \a targets_info. */
+static char *get_lb_uri_target_addresses(grpc_exec_ctx *exec_ctx,
+ const grpc_lb_addresses *addresses,
+ grpc_slice_hash_table **targets_info) {
+ size_t num_grpclb_addrs = 0;
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
+ }
+ /* All input addresses come from a resolver that claims they are LB services.
+ * It's the resolver's responsibility to make sure this policy is only
+ * instantiated and used in that case. Otherwise, something has gone wrong. */
+ GPR_ASSERT(num_grpclb_addrs > 0);
+
+ grpc_slice_hash_table_entry *targets_info_entries =
+ gpr_malloc(sizeof(*targets_info_entries) * num_grpclb_addrs);
+
+ /* construct a target ipvX://ip1:port1,ip2:port2,... from the addresses in \a
+ * addresses */
+ /* TODO(dgq): support mixed ip version */
+ char **addr_strs = gpr_malloc(sizeof(char *) * num_grpclb_addrs);
+ size_t addr_index = 0;
+
+ for (size_t i = 0; i < addresses->num_addresses; i++) {
+ if (addresses->addresses[i].user_data != NULL) {
+ gpr_log(GPR_ERROR,
+ "This LB policy doesn't support user data. It will be ignored");
+ }
+ if (addresses->addresses[i].is_balancer) {
+ char *addr_str;
+ GPR_ASSERT(grpc_sockaddr_to_string(
+ &addr_str, &addresses->addresses[i].address, true) > 0);
+ targets_info_entries[addr_index] = targets_info_entry_create(
+ addr_str, addresses->addresses[i].balancer_name);
+ addr_strs[addr_index++] = addr_str;
+ }
+ }
+ GPR_ASSERT(addr_index == num_grpclb_addrs);
+
+ size_t uri_path_len;
+ char *uri_path = gpr_strjoin_sep((const char **)addr_strs, num_grpclb_addrs,
+ ",", &uri_path_len);
+ for (size_t i = 0; i < num_grpclb_addrs; i++) gpr_free(addr_strs[i]);
+ gpr_free(addr_strs);
+
+ char *target_uri_str = NULL;
+ /* TODO(dgq): Don't assume all addresses will share the scheme of the first
+ * one */
+ gpr_asprintf(&target_uri_str, "%s:%s",
+ grpc_sockaddr_get_uri_scheme(&addresses->addresses[0].address),
+ uri_path);
+ gpr_free(uri_path);
+
+ *targets_info =
+ grpc_slice_hash_table_create(num_grpclb_addrs, targets_info_entries);
+ for (size_t i = 0; i < num_grpclb_addrs; i++) {
+ grpc_slice_unref_internal(exec_ctx, targets_info_entries[i].key);
+ }
+ gpr_free(targets_info_entries);
+
+ return target_uri_str;
+}
+
static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
grpc_lb_policy_factory *factory,
grpc_lb_policy_args *args) {
@@ -788,85 +880,30 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
}
grpc_uri_destroy(uri);
- /* All input addresses in addresses come from a resolver that claims
- * they are LB services. It's the resolver's responsibility to make sure
- * this policy is only instantiated and used in that case.
- *
- * Create a client channel over them to communicate with a LB service */
glb_policy->cc_factory = args->client_channel_factory;
glb_policy->args = grpc_channel_args_copy(args->args);
GPR_ASSERT(glb_policy->cc_factory != NULL);
- /* construct a target from the addresses in args, given in the form
- * ipvX://ip1:port1,ip2:port2,...
- * TODO(dgq): support mixed ip version */
- char **addr_strs = gpr_malloc(sizeof(char *) * num_grpclb_addrs);
- size_t addr_index = 0;
- for (size_t i = 0; i < addresses->num_addresses; i++) {
- if (addresses->addresses[i].user_data != NULL) {
- gpr_log(GPR_ERROR,
- "This LB policy doesn't support user data. It will be ignored");
- }
- if (addresses->addresses[i].is_balancer) {
- if (addr_index == 0) {
- addr_strs[addr_index++] =
- grpc_sockaddr_to_uri(&addresses->addresses[i].address);
- } else {
- GPR_ASSERT(grpc_sockaddr_to_string(&addr_strs[addr_index++],
- &addresses->addresses[i].address,
- true) > 0);
- }
- }
- }
- size_t uri_path_len;
- char *target_uri_str = gpr_strjoin_sep((const char **)addr_strs,
- num_grpclb_addrs, ",", &uri_path_len);
-
- /* Create a channel to talk to the LBs.
- *
- * We strip out the channel arg for the LB policy name, since we want
- * to use the default (pick_first) in this case.
- *
- * We also strip out the channel arg for the resolved addresses, since
- * that will be generated by the name resolver used in the LB channel.
- * Note that the LB channel will use the sockaddr resolver, so this
- * won't actually generate a query to DNS (or some other name service).
- * However, the addresses returned by the sockaddr resolver will have
- * is_balancer=false, whereas our own addresses have is_balancer=true.
- * We need the LB channel to return addresses with is_balancer=false
- * so that it does not wind up recursively using the grpclb LB policy,
- * as per the special case logic in client_channel.c.
- *
- * Finally, we also strip out the channel arg for the server URI,
- * since that will be different for the LB channel than for the parent
- * channel. (The client channel factory will re-add this arg with
- * the right value.)
- */
- static const char *keys_to_remove[] = {
- GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI};
- grpc_channel_args *new_args = grpc_channel_args_copy_and_remove(
- args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove));
- glb_policy->lb_channel = grpc_client_channel_factory_create_channel(
- exec_ctx, glb_policy->cc_factory, target_uri_str,
- GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, new_args);
- grpc_channel_args_destroy(exec_ctx, new_args);
-
- gpr_free(target_uri_str);
- for (size_t i = 0; i < num_grpclb_addrs; i++) {
- gpr_free(addr_strs[i]);
- }
- gpr_free(addr_strs);
-
+ grpc_slice_hash_table *targets_info = NULL;
+ /* Create a client channel over them to communicate with a LB service */
+ char *lb_service_target_addresses =
+ get_lb_uri_target_addresses(exec_ctx, addresses, &targets_info);
+ grpc_channel_args *lb_channel_args =
+ get_lb_channel_args(exec_ctx, targets_info, args->args);
+ glb_policy->lb_channel = grpc_lb_policy_grpclb_create_lb_channel(
+ exec_ctx, lb_service_target_addresses, args->client_channel_factory,
+ lb_channel_args);
+ grpc_slice_hash_table_unref(exec_ctx, targets_info);
+ grpc_channel_args_destroy(exec_ctx, lb_channel_args);
+ gpr_free(lb_service_target_addresses);
if (glb_policy->lb_channel == NULL) {
gpr_free(glb_policy);
return NULL;
}
-
grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable);
gpr_mu_init(&glb_policy->mu);
grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE,
"grpclb");
-
return &glb_policy->base;
}
diff --git a/src/core/ext/lb_policy/grpclb/grpclb_channel.c b/src/core/ext/lb_policy/grpclb/grpclb_channel.c
new file mode 100644
index 0000000000..1b8bbab1b6
--- /dev/null
+++ b/src/core/ext/lb_policy/grpclb/grpclb_channel.c
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/lb_policy/grpclb/grpclb_channel.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/support/string.h"
+
+grpc_channel *grpc_lb_policy_grpclb_create_lb_channel(
+ grpc_exec_ctx *exec_ctx, const char *lb_service_target_addresses,
+ grpc_client_channel_factory *client_channel_factory,
+ grpc_channel_args *args) {
+ grpc_channel *lb_channel = grpc_client_channel_factory_create_channel(
+ exec_ctx, client_channel_factory, lb_service_target_addresses,
+ GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, args);
+ return lb_channel;
+}
+
+grpc_channel_args *get_lb_channel_args(grpc_exec_ctx *exec_ctx,
+ grpc_slice_hash_table *targets_info,
+ const grpc_channel_args *args) {
+ /* We strip out the channel arg for the LB policy name, since we want
+ * to use the default (pick_first) in this case.
+ *
+ * We also strip out the channel arg for the resolved addresses, since
+ * that will be generated by the name resolver used in the LB channel.
+ * Note that the LB channel will use the sockaddr resolver, so this
+ * won't actually generate a query to DNS (or some other name service).
+ * However, the addresses returned by the sockaddr resolver will have
+ * is_balancer=false, whereas our own addresses have is_balancer=true.
+ * We need the LB channel to return addresses with is_balancer=false
+ * so that it does not wind up recursively using the grpclb LB policy,
+ * as per the special case logic in client_channel.c.
+ *
+ * Lastly, we also strip out the channel arg for the server URI,
+ * since that will be different for the LB channel than for the parent
+ * channel (the client channel factory will re-add this arg with
+ * the right value). */
+ static const char *keys_to_remove[] = {
+ GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI};
+ return grpc_channel_args_copy_and_remove(args, keys_to_remove,
+ GPR_ARRAY_SIZE(keys_to_remove));
+}
diff --git a/src/core/ext/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/lb_policy/grpclb/grpclb_channel.h
new file mode 100644
index 0000000000..f66082d78e
--- /dev/null
+++ b/src/core/ext/lb_policy/grpclb/grpclb_channel.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
+#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H
+
+#include "src/core/ext/client_channel/lb_policy_factory.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+
+/** Create the channel used for communicating with an LB service.
+ * Note that an LB *service* may be comprised of several LB *servers*.
+ *
+ * \a lb_service_target_addresses is the target URI containing the addresses
+ * from resolving the LB service's name (eg, ipv4:10.0.0.1:1234,10.2.3.4:9876).
+ * \a client_channel_factory will be used for the creation of the LB channel,
+ * alongside the channel args passed in \a args. */
+grpc_channel *grpc_lb_policy_grpclb_create_lb_channel(
+ grpc_exec_ctx *exec_ctx, const char *lb_service_target_addresses,
+ grpc_client_channel_factory *client_channel_factory,
+ grpc_channel_args *args);
+
+grpc_channel_args *get_lb_channel_args(grpc_exec_ctx *exec_ctx,
+ grpc_slice_hash_table *targets_info,
+ const grpc_channel_args *args);
+
+#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H */
diff --git a/src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c b/src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c
new file mode 100644
index 0000000000..2fee5f1b8e
--- /dev/null
+++ b/src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c
@@ -0,0 +1,107 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/lb_policy/grpclb/grpclb_channel.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/transport/lb_targets_info.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/support/string.h"
+
+grpc_channel *grpc_lb_policy_grpclb_create_lb_channel(
+ grpc_exec_ctx *exec_ctx, const char *lb_service_target_addresses,
+ grpc_client_channel_factory *client_channel_factory,
+ grpc_channel_args *args) {
+ grpc_channel_args *new_args = args;
+ grpc_channel_credentials *channel_credentials =
+ grpc_channel_credentials_find_in_args(args);
+ if (channel_credentials != NULL) {
+ /* Substitute the channel credentials with a version without call
+ * credentials: the load balancer is not necessarily trusted to handle
+ * bearer token credentials */
+ static const char *keys_to_remove[] = {GRPC_ARG_CHANNEL_CREDENTIALS};
+ grpc_channel_credentials *creds_sans_call_creds =
+ grpc_channel_credentials_duplicate_without_call_credentials(
+ channel_credentials);
+ GPR_ASSERT(creds_sans_call_creds != NULL);
+ grpc_arg args_to_add[] = {
+ grpc_channel_credentials_to_arg(creds_sans_call_creds)};
+ /* Create the new set of channel args */
+ new_args = grpc_channel_args_copy_and_add_and_remove(
+ args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), args_to_add,
+ GPR_ARRAY_SIZE(args_to_add));
+ grpc_channel_credentials_unref(exec_ctx, creds_sans_call_creds);
+ }
+ grpc_channel *lb_channel = grpc_client_channel_factory_create_channel(
+ exec_ctx, client_channel_factory, lb_service_target_addresses,
+ GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, new_args);
+ if (channel_credentials != NULL) {
+ grpc_channel_args_destroy(exec_ctx, new_args);
+ }
+ return lb_channel;
+}
+
+grpc_channel_args *get_lb_channel_args(grpc_exec_ctx *exec_ctx,
+ grpc_slice_hash_table *targets_info,
+ const grpc_channel_args *args) {
+ const grpc_arg targets_info_arg =
+ grpc_lb_targets_info_create_channel_arg(targets_info);
+ /* We strip out the channel arg for the LB policy name, since we want
+ * to use the default (pick_first) in this case.
+ *
+ * We also strip out the channel arg for the resolved addresses, since
+ * that will be generated by the name resolver used in the LB channel.
+ * Note that the LB channel will use the sockaddr resolver, so this
+ * won't actually generate a query to DNS (or some other name service).
+ * However, the addresses returned by the sockaddr resolver will have
+ * is_balancer=false, whereas our own addresses have is_balancer=true.
+ * We need the LB channel to return addresses with is_balancer=false
+ * so that it does not wind up recursively using the grpclb LB policy,
+ * as per the special case logic in client_channel.c.
+ *
+ * Lastly, we also strip out the channel arg for the server URI,
+ * since that will be different for the LB channel than for the parent
+ * channel (the client channel factory will re-add this arg with
+ * the right value). */
+ static const char *keys_to_remove[] = {
+ GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI};
+ /* Add the targets info table to be used for secure naming */
+ return grpc_channel_args_copy_and_add_and_remove(
+ args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &targets_info_arg,
+ 1);
+}
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index d17d8fa057..3e060d189a 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -739,6 +739,13 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
sc_args.args = new_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
+ if (grpc_lb_round_robin_trace) {
+ char *address_uri =
+ grpc_sockaddr_to_uri(&addresses->addresses[i].address);
+ gpr_log(GPR_DEBUG, "Created subchannel %p for address uri %s",
+ (void *)subchannel, address_uri);
+ gpr_free(address_uri);
+ }
grpc_channel_args_destroy(exec_ctx, new_args);
if (subchannel != NULL) {
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index d3e53984f2..d8c18eb122 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -40,10 +40,15 @@
#include "src/core/ext/client_channel/client_channel.h"
#include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/ext/client_channel/uri_parser.h"
#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/transport/lb_targets_info.h"
#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/slice/slice_hash_table.h"
+#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
@@ -53,12 +58,114 @@ static void client_channel_factory_ref(
static void client_channel_factory_unref(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory) {}
+static grpc_subchannel_args *get_secure_naming_subchannel_args(
+ grpc_exec_ctx *exec_ctx, const grpc_subchannel_args *args) {
+ grpc_channel_credentials *channel_credentials =
+ grpc_channel_credentials_find_in_args(args->args);
+ if (channel_credentials == NULL) {
+ gpr_log(GPR_ERROR,
+ "Can't create subchannel: channel credentials missing for secure "
+ "channel.");
+ return NULL;
+ }
+ // Make sure security connector does not already exist in args.
+ if (grpc_security_connector_find_in_args(args->args) != NULL) {
+ gpr_log(GPR_ERROR,
+ "Can't create subchannel: security connector already present in "
+ "channel args.");
+ return NULL;
+ }
+ // To which address are we connecting? By default, use the server URI.
+ const grpc_arg *server_uri_arg =
+ grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI);
+ GPR_ASSERT(server_uri_arg != NULL);
+ GPR_ASSERT(server_uri_arg->type == GRPC_ARG_STRING);
+ const char *server_uri_str = server_uri_arg->value.string;
+ GPR_ASSERT(server_uri_str != NULL);
+ grpc_uri *server_uri =
+ grpc_uri_parse(server_uri_str, true /* supress errors */);
+ GPR_ASSERT(server_uri != NULL);
+ const char *server_uri_path;
+ server_uri_path =
+ server_uri->path[0] == '/' ? server_uri->path + 1 : server_uri->path;
+ const grpc_slice_hash_table *targets_info =
+ grpc_lb_targets_info_find_in_args(args->args);
+ char *target_name_to_check = NULL;
+ if (targets_info != NULL) { // LB channel
+ // Find the balancer name for the target.
+ const char *target_uri_str =
+ grpc_get_subchannel_address_uri_arg(args->args);
+ grpc_uri *target_uri =
+ grpc_uri_parse(target_uri_str, false /* suppress errors */);
+ GPR_ASSERT(target_uri != NULL);
+ if (target_uri->path[0] != '\0') { // "path" may be empty
+ const grpc_slice key = grpc_slice_from_static_string(
+ target_uri->path[0] == '/' ? target_uri->path + 1 : target_uri->path);
+ const char *value = grpc_slice_hash_table_get(targets_info, key);
+ if (value != NULL) target_name_to_check = gpr_strdup(value);
+ grpc_slice_unref_internal(exec_ctx, key);
+ }
+ if (target_name_to_check == NULL) {
+ // If the target name to check hasn't already been set, fall back to using
+ // SERVER_URI
+ target_name_to_check = gpr_strdup(server_uri_path);
+ }
+ grpc_uri_destroy(target_uri);
+ } else { // regular channel: the secure name is the original server URI.
+ target_name_to_check = gpr_strdup(server_uri_path);
+ }
+ grpc_uri_destroy(server_uri);
+ GPR_ASSERT(target_name_to_check != NULL);
+ grpc_channel_security_connector *subchannel_security_connector = NULL;
+ // Create the security connector using the credentials and target name.
+ grpc_channel_args *new_args_from_connector = NULL;
+ const grpc_security_status security_status =
+ grpc_channel_credentials_create_security_connector(
+ exec_ctx, channel_credentials, target_name_to_check, args->args,
+ &subchannel_security_connector, &new_args_from_connector);
+ if (security_status != GRPC_SECURITY_OK) {
+ gpr_log(GPR_ERROR,
+ "Failed to create secure subchannel for secure name '%s'",
+ target_name_to_check);
+ gpr_free(target_name_to_check);
+ return NULL;
+ }
+ gpr_free(target_name_to_check);
+ grpc_arg new_security_connector_arg =
+ grpc_security_connector_to_arg(&subchannel_security_connector->base);
+
+ grpc_channel_args *new_args = grpc_channel_args_copy_and_add(
+ new_args_from_connector != NULL ? new_args_from_connector : args->args,
+ &new_security_connector_arg, 1);
+ GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &subchannel_security_connector->base,
+ "lb_channel_create");
+ if (new_args_from_connector != NULL) {
+ grpc_channel_args_destroy(exec_ctx, new_args_from_connector);
+ }
+ grpc_subchannel_args *final_sc_args = gpr_malloc(sizeof(*final_sc_args));
+ memcpy(final_sc_args, args, sizeof(*args));
+ final_sc_args->args = new_args;
+ return final_sc_args;
+}
+
static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) {
+ grpc_subchannel_args *subchannel_args =
+ get_secure_naming_subchannel_args(exec_ctx, args);
+ if (subchannel_args == NULL) {
+ gpr_log(
+ GPR_ERROR,
+ "Failed to create subchannel arguments during subchannel creation.");
+ return NULL;
+ }
grpc_connector *connector = grpc_chttp2_connector_create();
- grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
+ grpc_subchannel *s =
+ grpc_subchannel_create(exec_ctx, connector, subchannel_args);
grpc_connector_unref(exec_ctx, connector);
+ grpc_channel_args_destroy(exec_ctx,
+ (grpc_channel_args *)subchannel_args->args);
+ gpr_free(subchannel_args);
return s;
}
@@ -91,10 +198,10 @@ static const grpc_client_channel_factory_vtable client_channel_factory_vtable =
static grpc_client_channel_factory client_channel_factory = {
&client_channel_factory_vtable};
-/* Create a secure client channel:
- Asynchronously: - resolve target
- - connect to it (trying alternatives as presented)
- - perform handshakes */
+// Create a secure client channel:
+// Asynchronously: - resolve target
+// - connect to it (trying alternatives as presented)
+// - perform handshakes
grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
const char *target,
const grpc_channel_args *args,
@@ -103,47 +210,25 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
GRPC_API_TRACE(
"grpc_secure_channel_create(creds=%p, target=%s, args=%p, "
"reserved=%p)",
- 4, (creds, target, args, reserved));
+ 4, ((void *)creds, target, (void *)args, (void *)reserved));
GPR_ASSERT(reserved == NULL);
- // Make sure security connector does not already exist in args.
- if (grpc_find_security_connector_in_args(args) != NULL) {
- gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
+ grpc_channel *channel = NULL;
+ if (creds != NULL) {
+ // Add channel args containing the client channel factory and channel
+ // credentials.
+ grpc_arg args_to_add[] = {
+ grpc_client_channel_factory_create_channel_arg(&client_channel_factory),
+ grpc_channel_credentials_to_arg(creds)};
+ grpc_channel_args *new_args = grpc_channel_args_copy_and_add(
+ args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
+ // Create channel.
+ channel = client_channel_factory_create_channel(
+ &exec_ctx, &client_channel_factory, target,
+ GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args);
+ // Clean up.
+ grpc_channel_args_destroy(&exec_ctx, new_args);
grpc_exec_ctx_finish(&exec_ctx);
- return grpc_lame_client_channel_create(
- target, GRPC_STATUS_INTERNAL,
- "Security connector exists in channel args.");
- }
- // Create security connector and construct new channel args.
- grpc_channel_security_connector *security_connector;
- grpc_channel_args *new_args_from_connector;
- if (grpc_channel_credentials_create_security_connector(
- &exec_ctx, creds, target, args, &security_connector,
- &new_args_from_connector) != GRPC_SECURITY_OK) {
- grpc_exec_ctx_finish(&exec_ctx);
- return grpc_lame_client_channel_create(
- target, GRPC_STATUS_INTERNAL, "Failed to create security connector.");
- }
- // Add channel args containing the client channel factory and security
- // connector.
- grpc_arg args_to_add[2];
- args_to_add[0] =
- grpc_client_channel_factory_create_channel_arg(&client_channel_factory);
- args_to_add[1] = grpc_security_connector_to_arg(&security_connector->base);
- grpc_channel_args *new_args = grpc_channel_args_copy_and_add(
- new_args_from_connector != NULL ? new_args_from_connector : args,
- args_to_add, GPR_ARRAY_SIZE(args_to_add));
- if (new_args_from_connector != NULL) {
- grpc_channel_args_destroy(&exec_ctx, new_args_from_connector);
}
- // Create channel.
- grpc_channel *channel = client_channel_factory_create_channel(
- &exec_ctx, &client_channel_factory, target,
- GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args);
- // Clean up.
- GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &security_connector->base,
- "secure_client_channel_factory_create_channel");
- grpc_channel_args_destroy(&exec_ctx, new_args);
- grpc_exec_ctx_finish(&exec_ctx);
return channel != NULL ? channel
: grpc_lame_client_channel_create(
target, GRPC_STATUS_INTERNAL,
diff --git a/src/core/lib/iomgr/sockaddr_utils.c b/src/core/lib/iomgr/sockaddr_utils.c
index 44bc2f968b..ffa62cb53c 100644
--- a/src/core/lib/iomgr/sockaddr_utils.c
+++ b/src/core/lib/iomgr/sockaddr_utils.c
@@ -190,31 +190,37 @@ int grpc_sockaddr_to_string(char **out,
}
char *grpc_sockaddr_to_uri(const grpc_resolved_address *resolved_addr) {
- char *temp;
- char *result;
grpc_resolved_address addr_normalized;
- const struct sockaddr *addr;
-
if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
resolved_addr = &addr_normalized;
}
+ const char *scheme = grpc_sockaddr_get_uri_scheme(resolved_addr);
+ if (scheme == NULL || strcmp("unix", scheme) == 0) {
+ return grpc_sockaddr_to_uri_unix_if_possible(resolved_addr);
+ }
+ char *path = NULL;
+ char *uri_str = NULL;
+ if (grpc_sockaddr_to_string(&path, resolved_addr,
+ false /* suppress errors */) &&
+ scheme != NULL) {
+ gpr_asprintf(&uri_str, "%s:%s", scheme, path);
+ }
+ gpr_free(path);
+ return uri_str != NULL ? uri_str : NULL;
+}
- addr = (const struct sockaddr *)resolved_addr->addr;
-
+const char *grpc_sockaddr_get_uri_scheme(
+ const grpc_resolved_address *resolved_addr) {
+ const struct sockaddr *addr = (const struct sockaddr *)resolved_addr->addr;
switch (addr->sa_family) {
case AF_INET:
- grpc_sockaddr_to_string(&temp, resolved_addr, 0);
- gpr_asprintf(&result, "ipv4:%s", temp);
- gpr_free(temp);
- return result;
+ return "ipv4";
case AF_INET6:
- grpc_sockaddr_to_string(&temp, resolved_addr, 0);
- gpr_asprintf(&result, "ipv6:%s", temp);
- gpr_free(temp);
- return result;
- default:
- return grpc_sockaddr_to_uri_unix_if_possible(resolved_addr);
+ return "ipv6";
+ case AF_UNIX:
+ return "unix";
}
+ return NULL;
}
int grpc_sockaddr_get_port(const grpc_resolved_address *resolved_addr) {
diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h
index 5371e360c5..2b22f11b49 100644
--- a/src/core/lib/iomgr/sockaddr_utils.h
+++ b/src/core/lib/iomgr/sockaddr_utils.h
@@ -84,6 +84,10 @@ int grpc_sockaddr_set_port(const grpc_resolved_address *addr, int port);
int grpc_sockaddr_to_string(char **out, const grpc_resolved_address *addr,
int normalize);
+/* Returns the URI string corresponding to \a addr */
char *grpc_sockaddr_to_uri(const grpc_resolved_address *addr);
+/* Returns the URI scheme corresponding to \a addr */
+const char *grpc_sockaddr_get_uri_scheme(const grpc_resolved_address *addr);
+
#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */
diff --git a/src/core/lib/security/credentials/credentials.c b/src/core/lib/security/credentials/credentials.c
index 9781a22a86..b24697ce54 100644
--- a/src/core/lib/security/credentials/credentials.c
+++ b/src/core/lib/security/credentials/credentials.c
@@ -160,6 +160,53 @@ grpc_channel_credentials_duplicate_without_call_credentials(
}
}
+static void credentials_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
+ grpc_channel_credentials_unref(exec_ctx, p);
+}
+
+static void *credentials_pointer_arg_copy(void *p) {
+ return grpc_channel_credentials_ref(p);
+}
+
+static int credentials_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
+
+static const grpc_arg_pointer_vtable credentials_pointer_vtable = {
+ credentials_pointer_arg_copy, credentials_pointer_arg_destroy,
+ credentials_pointer_cmp};
+
+grpc_arg grpc_channel_credentials_to_arg(
+ grpc_channel_credentials *credentials) {
+ grpc_arg result;
+ result.type = GRPC_ARG_POINTER;
+ result.key = GRPC_ARG_CHANNEL_CREDENTIALS;
+ result.value.pointer.vtable = &credentials_pointer_vtable;
+ result.value.pointer.p = credentials;
+ return result;
+}
+
+grpc_channel_credentials *grpc_channel_credentials_from_arg(
+ const grpc_arg *arg) {
+ if (strcmp(arg->key, GRPC_ARG_CHANNEL_CREDENTIALS)) return NULL;
+ if (arg->type != GRPC_ARG_POINTER) {
+ gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
+ GRPC_ARG_CHANNEL_CREDENTIALS);
+ return NULL;
+ }
+ return arg->value.pointer.p;
+}
+
+grpc_channel_credentials *grpc_channel_credentials_find_in_args(
+ const grpc_channel_args *args) {
+ size_t i;
+ if (args == NULL) return NULL;
+ for (i = 0; i < args->num_args; i++) {
+ grpc_channel_credentials *credentials =
+ grpc_channel_credentials_from_arg(&args->args[i]);
+ if (credentials != NULL) return credentials;
+ }
+ return NULL;
+}
+
grpc_server_credentials *grpc_server_credentials_ref(
grpc_server_credentials *creds) {
if (creds == NULL) return NULL;
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index 3011df6b8a..510b79552a 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -100,6 +100,8 @@ void grpc_override_well_known_credentials_path_getter(
/* --- grpc_channel_credentials. --- */
+#define GRPC_ARG_CHANNEL_CREDENTIALS "grpc.channel_credentials"
+
typedef struct {
void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c);
@@ -140,6 +142,17 @@ grpc_channel_credentials *
grpc_channel_credentials_duplicate_without_call_credentials(
grpc_channel_credentials *creds);
+/* Util to encapsulate the channel credentials in a channel arg. */
+grpc_arg grpc_channel_credentials_to_arg(grpc_channel_credentials *credentials);
+
+/* Util to get the channel credentials from a channel arg. */
+grpc_channel_credentials *grpc_channel_credentials_from_arg(
+ const grpc_arg *arg);
+
+/* Util to find the channel credentials from channel args. */
+grpc_channel_credentials *grpc_channel_credentials_find_in_args(
+ const grpc_channel_args *args);
+
/* --- grpc_credentials_md. --- */
typedef struct {
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.c b/src/core/lib/security/credentials/fake/fake_credentials.c
index a8679d097d..a0629f76ce 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.c
+++ b/src/core/lib/security/credentials/fake/fake_credentials.c
@@ -35,13 +35,13 @@
#include <string.h>
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/iomgr/executor.h"
-
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/support/string.h"
+
/* -- Fake transport security credentials. -- */
static grpc_security_status fake_transport_security_create_security_connector(
@@ -49,7 +49,7 @@ static grpc_security_status fake_transport_security_create_security_connector(
grpc_call_credentials *call_creds, const char *target,
const grpc_channel_args *args, grpc_channel_security_connector **sc,
grpc_channel_args **new_args) {
- *sc = grpc_fake_channel_security_connector_create(call_creds);
+ *sc = grpc_fake_channel_security_connector_create(call_creds, target, args);
return GRPC_SECURITY_OK;
}
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h
index 9cf38084a3..0fe98417c6 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.h
+++ b/src/core/lib/security/credentials/fake/fake_credentials.h
@@ -38,6 +38,21 @@
/* -- Fake transport security credentials. -- */
+/* Used to verify the target names given to the fake transport security
+ * connector.
+ *
+ * Its syntax by example:
+ * For LB channels:
+ * "backend_target_1,backend_target_2,...;lb_target_1,lb_target_2,..."
+ * For regular channels:
+ * "backend_taget_1,backend_target_2,..."
+ *
+ * That is to say, LB channels have a heading list of LB targets separated from
+ * the list of backend targets by a semicolon. For non-LB channels, only the
+ * latter is present. */
+#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
+ "grpc.test_only.fake_security.expected_target"
+
/* Creates a fake transport security credentials object for testing. */
grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void);
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index cf056e8008..b9bbe1b304 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -335,7 +335,7 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
grpc_security_connector *sc =
- grpc_find_security_connector_in_args(args->channel_args);
+ grpc_security_connector_find_in_args(args->channel_args);
grpc_auth_context *auth_context =
grpc_find_auth_context_in_args(args->channel_args);
diff --git a/src/core/lib/security/transport/lb_targets_info.c b/src/core/lib/security/transport/lb_targets_info.c
new file mode 100644
index 0000000000..e73483c039
--- /dev/null
+++ b/src/core/lib/security/transport/lb_targets_info.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/transport/lb_targets_info.h"
+
+/* Channel arg key for the mapping of LB server addresses to their names for
+ * secure naming purposes. */
+#define GRPC_ARG_LB_SECURE_NAMING_MAP "grpc.lb_secure_naming_map"
+
+static void *targets_info_copy(void *p) { return grpc_slice_hash_table_ref(p); }
+static void targets_info_destroy(grpc_exec_ctx *exec_ctx, void *p) {
+ grpc_slice_hash_table_unref(exec_ctx, p);
+}
+static int targets_info_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
+static const grpc_arg_pointer_vtable server_to_balancer_names_vtable = {
+ targets_info_copy, targets_info_destroy, targets_info_cmp};
+
+grpc_arg grpc_lb_targets_info_create_channel_arg(
+ grpc_slice_hash_table *targets_info) {
+ grpc_arg arg;
+ arg.type = GRPC_ARG_POINTER;
+ arg.key = GRPC_ARG_LB_SECURE_NAMING_MAP;
+ arg.value.pointer.p = targets_info;
+ arg.value.pointer.vtable = &server_to_balancer_names_vtable;
+ return arg;
+}
+
+grpc_slice_hash_table *grpc_lb_targets_info_find_in_args(
+ const grpc_channel_args *args) {
+ const grpc_arg *targets_info_arg =
+ grpc_channel_args_find(args, GRPC_ARG_LB_SECURE_NAMING_MAP);
+ if (targets_info_arg != NULL) {
+ GPR_ASSERT(targets_info_arg->type == GRPC_ARG_POINTER);
+ return targets_info_arg->value.pointer.p;
+ }
+ return NULL;
+}
diff --git a/src/core/lib/security/transport/lb_targets_info.h b/src/core/lib/security/transport/lb_targets_info.h
new file mode 100644
index 0000000000..5e6cacc197
--- /dev/null
+++ b/src/core/lib/security/transport/lb_targets_info.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
+#define GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
+
+#include "src/core/lib/slice/slice_hash_table.h"
+
+/** Return a channel argument containing \a targets_info. */
+grpc_arg grpc_lb_targets_info_create_channel_arg(
+ grpc_slice_hash_table *targets_info);
+
+/** Return the instance of targets info in \a args or NULL */
+grpc_slice_hash_table *grpc_lb_targets_info_find_in_args(
+ const grpc_channel_args *args);
+
+#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H */
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index b09127811b..aeb04e33a3 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -43,10 +43,13 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/alpn/alpn.h"
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/credentials/fake/fake_credentials.h"
+#include "src/core/lib/security/transport/lb_targets_info.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/env.h"
@@ -205,23 +208,23 @@ static const grpc_arg_pointer_vtable connector_pointer_vtable = {
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
grpc_arg result;
result.type = GRPC_ARG_POINTER;
- result.key = GRPC_SECURITY_CONNECTOR_ARG;
+ result.key = GRPC_ARG_SECURITY_CONNECTOR;
result.value.pointer.vtable = &connector_pointer_vtable;
result.value.pointer.p = sc;
return result;
}
grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
- if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
+ if (strcmp(arg->key, GRPC_ARG_SECURITY_CONNECTOR)) return NULL;
if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
- GRPC_SECURITY_CONNECTOR_ARG);
+ GRPC_ARG_SECURITY_CONNECTOR);
return NULL;
}
return arg->value.pointer.p;
}
-grpc_security_connector *grpc_find_security_connector_in_args(
+grpc_security_connector *grpc_security_connector_find_in_args(
const grpc_channel_args *args) {
size_t i;
if (args == NULL) return NULL;
@@ -235,11 +238,21 @@ grpc_security_connector *grpc_find_security_connector_in_args(
/* -- Fake implementation. -- */
+typedef struct {
+ grpc_channel_security_connector base;
+ char *target;
+ char *expected_targets;
+ bool is_lb_channel;
+} grpc_fake_channel_security_connector;
+
static void fake_channel_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
- grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
- grpc_call_credentials_unref(exec_ctx, c->request_metadata_creds);
- gpr_free(sc);
+ grpc_fake_channel_security_connector *c =
+ (grpc_fake_channel_security_connector *)sc;
+ grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds);
+ gpr_free(c->target);
+ gpr_free(c->expected_targets);
+ gpr_free(c);
}
static void fake_server_destroy(grpc_exec_ctx *exec_ctx,
@@ -247,6 +260,68 @@ static void fake_server_destroy(grpc_exec_ctx *exec_ctx,
gpr_free(sc);
}
+static bool fake_check_target(const char *target_type, const char *target,
+ const char *set_str) {
+ GPR_ASSERT(target_type != NULL);
+ GPR_ASSERT(target != NULL);
+ char **set = NULL;
+ size_t set_size = 0;
+ gpr_string_split(set_str, ",", &set, &set_size);
+ bool found = false;
+ for (size_t i = 0; i < set_size; ++i) {
+ if (set[i] != NULL && strcmp(target, set[i]) == 0) found = true;
+ }
+ for (size_t i = 0; i < set_size; ++i) {
+ gpr_free(set[i]);
+ }
+ gpr_free(set);
+ return found;
+}
+
+static void fake_secure_name_check(const char *target,
+ const char *expected_targets,
+ bool is_lb_channel) {
+ if (expected_targets == NULL) return;
+ char **lbs_and_backends = NULL;
+ size_t lbs_and_backends_size = 0;
+ bool success = false;
+ gpr_string_split(expected_targets, ";", &lbs_and_backends,
+ &lbs_and_backends_size);
+ if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) {
+ gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'",
+ expected_targets);
+ goto done;
+ }
+ if (is_lb_channel) {
+ if (lbs_and_backends_size != 2) {
+ gpr_log(GPR_ERROR,
+ "Invalid expected targets arg value: '%s'. Expectations for LB "
+ "channels must be of the form 'be1,be2,be3,...;lb1,lb2,...",
+ expected_targets);
+ goto done;
+ }
+ if (!fake_check_target("LB", target, lbs_and_backends[1])) {
+ gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'",
+ target, lbs_and_backends[1]);
+ goto done;
+ }
+ success = true;
+ } else {
+ if (!fake_check_target("Backend", target, lbs_and_backends[0])) {
+ gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'",
+ target, lbs_and_backends[0]);
+ goto done;
+ }
+ success = true;
+ }
+done:
+ for (size_t i = 0; i < lbs_and_backends_size; ++i) {
+ gpr_free(lbs_and_backends[i]);
+ }
+ gpr_free(lbs_and_backends);
+ if (!success) abort();
+}
+
static void fake_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
grpc_auth_context **auth_context,
@@ -277,12 +352,28 @@ static void fake_check_peer(grpc_exec_ctx *exec_ctx,
grpc_auth_context_add_cstring_property(
*auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
-
end:
grpc_closure_sched(exec_ctx, on_peer_checked, error);
tsi_peer_destruct(&peer);
}
+static void fake_channel_check_peer(grpc_exec_ctx *exec_ctx,
+ grpc_security_connector *sc, tsi_peer peer,
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
+ fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
+ grpc_fake_channel_security_connector *c =
+ (grpc_fake_channel_security_connector *)sc;
+ fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel);
+}
+
+static void fake_server_check_peer(grpc_exec_ctx *exec_ctx,
+ grpc_security_connector *sc, tsi_peer peer,
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
+ fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
+}
+
static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
const char *host,
@@ -313,22 +404,32 @@ static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx,
}
static grpc_security_connector_vtable fake_channel_vtable = {
- fake_channel_destroy, fake_check_peer};
+ fake_channel_destroy, fake_channel_check_peer};
-static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy,
- fake_check_peer};
+static grpc_security_connector_vtable fake_server_vtable = {
+ fake_server_destroy, fake_server_check_peer};
grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
- grpc_call_credentials *request_metadata_creds) {
- grpc_channel_security_connector *c = gpr_malloc(sizeof(*c));
+ grpc_call_credentials *request_metadata_creds, const char *target,
+ const grpc_channel_args *args) {
+ grpc_fake_channel_security_connector *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
- gpr_ref_init(&c->base.refcount, 1);
- c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
- c->base.vtable = &fake_channel_vtable;
- c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
- c->check_call_host = fake_channel_check_call_host;
- c->add_handshakers = fake_channel_add_handshakers;
- return c;
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
+ c->base.base.vtable = &fake_channel_vtable;
+ c->base.request_metadata_creds =
+ grpc_call_credentials_ref(request_metadata_creds);
+ c->base.check_call_host = fake_channel_check_call_host;
+ c->base.add_handshakers = fake_channel_add_handshakers;
+ c->target = gpr_strdup(target);
+ const grpc_arg *expected_target_arg =
+ grpc_channel_args_find(args, GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS);
+ if (expected_target_arg != NULL) {
+ GPR_ASSERT(expected_target_arg->type == GRPC_ARG_STRING);
+ c->expected_targets = gpr_strdup(expected_target_arg->value.string);
+ }
+ c->is_lb_channel = (grpc_lb_targets_info_find_in_args(args) != NULL);
+ return &c->base;
}
grpc_server_security_connector *grpc_fake_server_security_connector_create(
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index eba4e6d1d7..3df2fecd39 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -57,7 +57,7 @@ typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
typedef struct grpc_security_connector grpc_security_connector;
-#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
+#define GRPC_ARG_SECURITY_CONNECTOR "grpc.security_connector"
typedef struct {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc);
@@ -115,7 +115,7 @@ grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg);
/* Util to find the connector from channel args. */
-grpc_security_connector *grpc_find_security_connector_in_args(
+grpc_security_connector *grpc_security_connector_find_in_args(
const grpc_channel_args *args);
/* --- channel_security_connector object. ---
@@ -175,7 +175,8 @@ void grpc_server_security_connector_add_handshakers(
/* For TESTING ONLY!
Creates a fake connector that emulates real channel security. */
grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
- grpc_call_credentials *request_metadata_creds);
+ grpc_call_credentials *request_metadata_creds, const char *target,
+ const grpc_channel_args *args);
/* For TESTING ONLY!
Creates a fake connector that emulates real server security. */
diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c
index bb8a3bf6cd..5d57543ac5 100644
--- a/src/core/lib/security/transport/security_handshaker.c
+++ b/src/core/lib/security/transport/security_handshaker.c
@@ -451,7 +451,7 @@ static void client_handshaker_factory_add_handshakers(
grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory,
const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) {
grpc_channel_security_connector *security_connector =
- (grpc_channel_security_connector *)grpc_find_security_connector_in_args(
+ (grpc_channel_security_connector *)grpc_security_connector_find_in_args(
args);
grpc_channel_security_connector_add_handshakers(exec_ctx, security_connector,
handshake_mgr);
@@ -461,7 +461,7 @@ static void server_handshaker_factory_add_handshakers(
grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *hf,
const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) {
grpc_server_security_connector *security_connector =
- (grpc_server_security_connector *)grpc_find_security_connector_in_args(
+ (grpc_server_security_connector *)grpc_security_connector_find_in_args(
args);
grpc_server_security_connector_add_handshakers(exec_ctx, security_connector,
handshake_mgr);
diff --git a/src/core/lib/surface/init_secure.c b/src/core/lib/surface/init_secure.c
index a44407d3bb..46b9a8f922 100644
--- a/src/core/lib/surface/init_secure.c
+++ b/src/core/lib/surface/init_secure.c
@@ -56,7 +56,7 @@ static bool maybe_prepend_client_auth_filter(
grpc_channel_stack_builder_get_channel_arguments(builder);
if (args) {
for (size_t i = 0; i < args->num_args; i++) {
- if (0 == strcmp(GRPC_SECURITY_CONNECTOR_ARG, args->args[i].key)) {
+ if (0 == strcmp(GRPC_ARG_SECURITY_CONNECTOR, args->args[i].key)) {
return grpc_channel_stack_builder_prepend_filter(
builder, &grpc_client_auth_filter, NULL, NULL);
}
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 6bca3ed1a5..a9f20e6d2a 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -231,6 +231,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_credentials.c',
'src/core/lib/security/transport/client_auth_filter.c',
+ 'src/core/lib/security/transport/lb_targets_info.c',
'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.c',
@@ -271,6 +272,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
'src/core/ext/lb_policy/grpclb/grpclb.c',
+ 'src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',