diff --git a/webserver/doskast-trigger-connect.c b/webserver/doskast-trigger-connect.c new file mode 100644 index 0000000..80fe989 --- /dev/null +++ b/webserver/doskast-trigger-connect.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// allow to redefine as gcc -D... +#ifndef DIR +#define DIR "/tmp" +#endif + +#define HTTP_OK 200 +#define HTTP_BAD_REQUEST 400 +#define HTTP_ERROR 500 + +/* Here we could verify validity of a IPv4 or IPv6 address, + * but that is very complex. Just sanitize input. */ +int +_verify_ip(char *ip){ + int rc = 0; + for (int i = 0; i < strlen(ip); i++){ + if (!( (ip[i] == '.') || /* IPv4 dots */ + (ip[i] == ':') || /* IPv6 */ + (ip[i] == '/') || /* XXX Is it needed for IPv6? */ + (isalnum(ip[i]) > 0) /* Numbers (v4 and v6) and letters (v6) */ + )) { + rc = i; + break; + } + } + return rc; +} + +/* Generate a random alphanum sequence + * Example: 10841ee0cc4f (12 chars) */ +int +_rand(char **rs){ + // https://books.google.ru/books?id=1nG3BwAAQBAJ + // hex.data will be 6x2=12 chars + unsigned char buf_rnd[6]; + gnutls_datum_t rnd = { buf_rnd, sizeof(buf_rnd) }; + int rc; + rc = gnutls_rnd(GNUTLS_RND_NONCE, rnd.data, rnd.size); + if (rc != GNUTLS_E_SUCCESS) { + printf("Error in gnutls_rnd()"); + goto out; + } + gnutls_datum_t hex; + rc = gnutls_hex_encode2(&rnd, &hex); + if (rc != GNUTLS_E_SUCCESS) { + printf("Error in gnutls_hex_encode2()"); + goto out; + } + *rs = malloc(hex.size); + rc = sprintf(*rs, "%s", hex.data); + if (rc < 0) { + printf("Error in sprintf()"); + goto out; + } +out: + return rc; +} + +int +main(){ + int rc = 0; + int http_code = HTTP_ERROR; + if (access(DIR, W_OK) != 0) { + fprintf(stderr, "Directory %s does not exist or is not writable\n", DIR); + http_code = HTTP_ERROR; + goto out; + } + // first chdir() and then chroot()! + if (!( chdir(DIR) == 0 && chroot(DIR) == 0 )) { + fprintf(stderr, "Cannot chdir and chroot into %s\n", DIR); + http_code = HTTP_ERROR; + goto out; + } + while(FCGI_Accept() >= 0) { + char *ip = getenv("REMOTE_ADDR"); + if (ip == NULL) { + fprintf(stderr, "%s\n", "Env REMOTE_ADDR is not set"); + http_code = HTTP_ERROR; + goto fcgi_out; + } + rc = _verify_ip(ip); + if (rc != 0) { + fprintf(stderr, "%s\n", "Incorrect REMOTE_ADDR"); + http_code = HTTP_BAD_REQUEST; + goto fcgi_out; + } + char *hex; + int max_try = 10; + for (int i = 1; i <= max_try; i++) { + if (i == max_try) { + fprintf(stderr, "%s\n", "Error in random file loop"); + http_code = HTTP_ERROR; + goto fcgi_out; + } + rc = _rand(&hex); + if (rc < 0) { + fprintf(stderr, "Error in _rand()"); + continue; + } + if (access(hex, F_OK) != 0) { + break; + } + } + FCGI_FILE *d = fopen(hex, "w"); + fprintf(d, "%s", ip); + fclose(d); + http_code = HTTP_OK; +fcgi_out: + printf("Status: %d\n", http_code); + printf("Content-Type: text/plain; charset=utf-8\n"); + if (http_code == HTTP_OK) { + printf("%s\n", "OK"); + rc = 0; + } else { + rc = 1; + } + } +out: + return rc; +}