SSL_connect 在 c++ 中失败但我可以通过 python 连接

发布于 2025-01-11 04:13:47 字数 2080 浏览 0 评论 0原文

我想使用套接字向 api 发送请求。

我知道该服务正在运行,因为 python 中的遗留代码可以正常工作。请参阅下面的摘录:

class SocketConnection:
    def __init__(self, payload, host):
        self.payload = payload
        self.host = host
        self.sock = None
        self.response_text = {}
        self.status_code = None
        self.full_resp = ""

    def connect(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        context = ssl.create_default_context()
        sock = context.wrap_socket(sock, server_hostname=self.host)
        sock.connect((self.host, 443))
        self.sock = sock

    def send(self):
        self.sock.send(self.payload)

    def receive(self):
        self.full_resp = self.sock.recv(4096).decode("utf-8")
        self.response_text = [self.full_resp]
        self.status_code = self.full_resp[9:12]
        self.sock.close()

我有以下 C++ 代码,它总是会成功找到它可以连接到的地址,但永远找不到通过 SSL_connect 的地址。 SSL_get_error 返回 1。

array<struct addrinfo*, 2> get_valid_addrinfo(string s) {
  struct addrinfo *res;
  struct addrinfo hints;
  memset(&hints, '\0', sizeof(hints));
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_family = AF_INET;
  hints.ai_flags = AI_ADDRCONFIG;
  int e = getaddrinfo(s.c_str(), "https", &hints, &res);
  if (e != 0) {
    printf("failure %s\n", gai_strerror (e));
    assert(-1);
  }
  int sock = -1;
  struct addrinfo *r ;
  SSL_CTX * ctx = make_ssl_context();
  SSL * ssl;
  for (r = res; r != NULL; r = r->ai_next) {
    sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
    if (sock != -1 && connect(sock, r->ai_addr, r->ai_addrlen) == 0) {
      free(ssl);
      ssl = SSL_new(ctx);
      SSL_set_fd(ssl, sock);
      if (SSL_connect(ssl) != -1)
        break;
    }
    if (sock != -1) {
       close(sock);
       sock = -1;
    }
  }
  assert(sock != -1);
  close(sock);
  free(ssl);
  SSL_CTX_free(ctx);
  return {res, r};
}

我使用的是 debian 10。

我做错了什么?

I want to send a request to an api using a socket.

I know the service is running as the legacy code in python works. See an excerpt below:

class SocketConnection:
    def __init__(self, payload, host):
        self.payload = payload
        self.host = host
        self.sock = None
        self.response_text = {}
        self.status_code = None
        self.full_resp = ""

    def connect(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        context = ssl.create_default_context()
        sock = context.wrap_socket(sock, server_hostname=self.host)
        sock.connect((self.host, 443))
        self.sock = sock

    def send(self):
        self.sock.send(self.payload)

    def receive(self):
        self.full_resp = self.sock.recv(4096).decode("utf-8")
        self.response_text = [self.full_resp]
        self.status_code = self.full_resp[9:12]
        self.sock.close()

I have the following C++ code which will always succeed in finding an address it can connect to, but can never find one that passes SSL_connect. SSL_get_error returns 1.

array<struct addrinfo*, 2> get_valid_addrinfo(string s) {
  struct addrinfo *res;
  struct addrinfo hints;
  memset(&hints, '\0', sizeof(hints));
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_family = AF_INET;
  hints.ai_flags = AI_ADDRCONFIG;
  int e = getaddrinfo(s.c_str(), "https", &hints, &res);
  if (e != 0) {
    printf("failure %s\n", gai_strerror (e));
    assert(-1);
  }
  int sock = -1;
  struct addrinfo *r ;
  SSL_CTX * ctx = make_ssl_context();
  SSL * ssl;
  for (r = res; r != NULL; r = r->ai_next) {
    sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
    if (sock != -1 && connect(sock, r->ai_addr, r->ai_addrlen) == 0) {
      free(ssl);
      ssl = SSL_new(ctx);
      SSL_set_fd(ssl, sock);
      if (SSL_connect(ssl) != -1)
        break;
    }
    if (sock != -1) {
       close(sock);
       sock = -1;
    }
  }
  assert(sock != -1);
  close(sock);
  free(ssl);
  SSL_CTX_free(ctx);
  return {res, r};
}

I'm on debian 10.

What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白日梦 2025-01-18 04:13:47

在尝试修复代码之前,您应该向其添加一些适当的错误报告,这样您就不会在黑暗中进行尝试。当 OpenSSL 调用失败时,您可以执行以下操作:

unsigned long e = ERR_get_error ();
char errbuf [120];             // magic number, documented!
ERR_error_string (e, errbuf);

然后按照您的意愿报告错误。

我发现 ERR_error_string 返回的字符串特别有用,事实上 OpenSSL 维护着一个称为“错误堆栈”的东西,因此您应该循环 ERR_get_error 直到它返回零(或者,如果您只想报告第一个错误,则可以调用 ERR_clear_error,但在继续之前以某种方式清除错误堆栈非常重要)。如果您浏览文档,您可以阅读所有这些内容。

我看到 Steffen 刚刚回答了您的其他问题,所以我不需要再写任何内容 :) 但我确实知道像 Cloudflare 这样的云服务提供商需要这个。

Before you try to fix your code, you should add some proper error reporting to it so that you're not shooting in the dark. When an OpenSSL call fails, you can do:

unsigned long e = ERR_get_error ();
char errbuf [120];             // magic number, documented!
ERR_error_string (e, errbuf);

And then report the error however you wish.

I find the string returned by ERR_error_string particularly useful, and in fact OpenSSL maintains something called an 'error stack', so you should loop on ERR_get_error until it returns zero (or, if you only want to report the first error, you can call ERR_clear_error instead, but it's important to clear the error stack one way or another before you move on). If you browse the docs, you can read up on all this stuff.

And I see that Steffen has just answered your other query, so I don't need to write anything more :) I do know however that cloud service providers like Cloudflare need this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文