#include #include #include #include #include #include #include #include "purr.h" int clean_up_link(const char *dirty, char *clean, char *path, char *port) { // detect protocol, remove protocol prefix int portn = 0; const char *first_colon = strchr(dirty, ':'); const char *start_link = NULL; if (first_colon == NULL) { // no protocol specified, default to HTTP portn = HTTP_PORT; start_link = dirty; } else { if (strstr(dirty, "https://") != NULL) { portn = HTTPS_PORT; } else if (strstr(dirty, "http://") != NULL) { portn = HTTP_PORT; } else { fputs("clean_up_link(): unknown protocol!\n", stderr); return -1; } if (first_colon[1] == '/' && first_colon[2] == '/') { // correct format start_link = first_colon + 3; } else { fputs("clean_up_link(): bad header!\n", stderr); return -1; } } // maximum size necessary strlcpy(clean, start_link, 254); char *slash = strchr(clean, '/'); if (slash != NULL) { // copy to path strlcpy(path, slash, 1024); // slashes found at the end of the link *slash = 0; } else { path[0] = '/'; path[1] = 0; } sprintf(port, "%d", portn); return portn; } #define MALFORM_ERROR(p) do{if((p) == NULL || (p)[1] == 0) {fputs("get_encryption_params(): malformed URL\n", stderr); return rv;}}while(0); int get_encryption_params(char *path, uint8_t **keyp, uint8_t **ivp) { int rv = -1; // parse path in format: "/paste.html#_[_]" // will update path to point to the proper piece uint8_t *key = calloc(KEY_LEN, 1); uint8_t *iv = calloc(IV_LEN, 1); char *path_temp = calloc(strlen(path), 1); if (key == NULL || iv == NULL || path_temp == NULL) { perror("calloc()"); return rv; } *keyp = key; *ivp = iv; char *hash = strchr(path, '#'); MALFORM_ERROR(hash); char *underscore = strchr(hash + 1, '_'); MALFORM_ERROR(underscore); underscore[0] = 0; sprintf(path_temp, "/%s", hash + 1); char *key_start = underscore + 1; underscore = strchr(key_start, '_'); MALFORM_ERROR(underscore); underscore[0] = 0; char *iv_start = underscore + 1; size_t key_s_len = strlen(key_start), iv_s_len = strlen(iv_start); // odd number of chars is an error, as well as being too big if (key_s_len & 1 || iv_s_len & 1 || key_s_len / 2 > KEY_LEN || iv_s_len / 2 > IV_LEN) { fputs("get_encryption_params(): malformed KEY and/or IV input\n", stderr); return rv; } int err = decode_hex(key_start, key, key_s_len / 2) | decode_hex(iv_start, iv, iv_s_len / 2); if (err) { fputs("get_encryption_params(): malformed KEY and/or IV input\n", stderr); return rv; } strcpy(path, path_temp); free(path_temp); rv = 0; return rv; } int host_connect(const char *host, const char *port, bool debug) { struct addrinfo hints = { 0 }, *si = NULL; int fd = 0, err = 0; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; err = getaddrinfo(host, port, &hints, &si); if (err) { fprintf(stderr, "fail at getaddrinfo: %s\n", gai_strerror(err)); return -1; } for (struct addrinfo *p = si; p != NULL; p = p->ai_next) { void *addr; char ip_addr[INET6_ADDRSTRLEN] = { 0 }; // use struct based on connection type if (p->ai_family == AF_INET) { struct sockaddr_in *remote = (struct sockaddr_in *)p->ai_addr; addr = &remote->sin_addr; } else if (p->ai_family == AF_INET6) { struct sockaddr_in6 *remote = (struct sockaddr_in6 *)p->ai_addr; addr = &remote->sin6_addr; } else { fputs("host_connect(): unsupported addr result\n", stderr); continue; } inet_ntop(p->ai_family, addr, ip_addr, INET6_ADDRSTRLEN); if (debug) fprintf(stderr, "IP addr: %s\n", ip_addr); // try to establish connection fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (fd < 0) { perror("couldn't create socket"); continue; } if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) { perror("couldn't connect to socket"); close(fd); continue; } // only use first addr, for now break; } freeaddrinfo(si); return fd; }