#include "sockets.h" // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); } // Create socket to connect to real IRC server int createserversocket(char *host, char *port) { int sockfd; struct addrinfo hints, *servinfo, *p; int rv;// return value for getaddrinfo (for error message) char s[INET6_ADDRSTRLEN]; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and connect to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("bouncer-server: socket"); continue; } if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("bouncer-server: connect"); continue; } break; } if (p == NULL) { fprintf(stderr, "bouncer-server: failed to connect\n"); return 2; } inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); printf("bouncer-server: connecting to %s\n", s); freeaddrinfo(servinfo); // all done with this structure return sockfd; } // Create listening socket to listen for bouncer client connections int createclientsocket(char *listenport) { int listener; // listening socket descriptor int rv; // return value for getaddrinfo (for error message) struct addrinfo hints, *ai, *p; int yes = 1; // for enabling socket options with setsockopt // get us a socket and bind it memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if ((rv = getaddrinfo(NULL, listenport, &hints, &ai)) != 0) { fprintf(stderr, "bouncer-client: %s\n", gai_strerror(rv)); exit(1); } // Try for IPv6 for (p = ai; p != NULL; p = p->ai_next) { if (p->ai_family == AF_INET6) { listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (listener != -1) { // success, got IPv6! printf("success, got IPv6! ai_family: %d\n", p->ai_family); break; } } } // Try for IPv4 if IPv6 failed if (listener < 0) { for (p = ai; p != NULL; p = p->ai_next) { if (p->ai_family == AF_INET) { listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (listener != -1) { // moderate success, got IPv4! printf("moderate success, got IPv4! ai_family: %d\n", p->ai_family); break; } } } } // allow address re-use setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); // 1 as in non-zero as in enable if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) { // failed to bind close(listener); printf("bouncer-client: failed to bind, exiting...\n"); exit(1); } // if we got here, it means we didn't get bound if (p == NULL) { fprintf(stderr, "bouncer-client: failed to bind\n"); exit(2); } freeaddrinfo(ai); // all done with this // listen if (listen(listener, BACKLOG) == -1) { perror("listen"); exit(1); } return listener; } void init_openssl() { SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); } void cleanup_openssl() { EVP_cleanup(); } // Create OpenSSL context, type = 0 for IRC server-side (OpenSSL client) // or type = 1 for bouncer client-side (OpenSSL server) SSL_CTX *create_openssl_context(int type) { const SSL_METHOD *method; SSL_CTX *ctx; if (type == 0) { method = SSLv23_client_method(); } else { method = SSLv23_server_method(); } ctx = SSL_CTX_new(method); if (!ctx) { perror("Unable to create SSL context"); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } return ctx; } // Configure OpenSSL context, with certfile and keyfile provided if // IRC server-side or set to NULL if bouncer client-side void configure_openssl_context(SSL_CTX *ctx, char *certfile, char *keyfile) { SSL_CTX_set_ecdh_auto(ctx, 1); /* Set the key and cert if set or return if not */ if (certfile == NULL || keyfile == NULL) { return; } if (SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } if (SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM) <= 0 ) { ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } } // Read from a socket, whether or not using TLS int sockread(SSL *fd, char *buf, int bufsize, int tls) { if (tls) { return SSL_read(fd, buf, bufsize); } else { // Cast the supposed SSL *fd to a long int if we're not using TLS return recv((long int)fd, buf, bufsize, 0); } } // Write to a socket, whether or not using TLS int socksend(SSL *fd, char *buf, int bufsize, int tls) { if (tls) { return SSL_write(fd, buf, bufsize); } else { // Cast the supposed SSL *fd to a long int if we're not using TLS return send((long int)fd, buf, bufsize, 0); } }