0

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?

4
  • 1
    Nothing is known about the requirements of the server - and there is no way to check because nothing is known about the server. Nothing is known about the exact error - please get this with ERR_get_error. A major difference between the C++ code and the Python code is that the latter uses SNI (server_hostname=self.host) and the C++ code not. Try to omit this option from Python and see if it still works. Commented Mar 2, 2022 at 18:29
  • @SteffenUllrich python just says the hostname is required if i ommit it or set it to an empty string. I've never heard of SNI. How can I use it in the cpp code? Commented Mar 2, 2022 at 18:38
  • 2
    "I've never heard of SNI. How can I use it in the cpp code?" - see How to implement Server Name Indication (SNI). "python just says the hostname is required" - set context.check_hostname=False. Commented Mar 2, 2022 at 18:45
  • @SteffenUllrich I added SNI and it worked - if you write this as an answer i'll accept it. Commented Mar 2, 2022 at 20:29

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

what would be a good resource to follow to learn more about openssl - the docs are very dense and not too easy to navigate around
Sorry, I can't help you there. I agree with you about the docs, but I managed to bluff my way through. SNI had me going for a while though. But do make sure to put proper error checking (and reporting) in. When Discogs moved to Cloudflare and broke my app, it saved my bacon. [pause]. A quick nose around found this. It's mostly conceptual, but at least it's a start.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.