diff --git a/src/apps/relay/http_server.c b/src/apps/relay/http_server.c
index ff8e399..ca70d77 100644
--- a/src/apps/relay/http_server.c
+++ b/src/apps/relay/http_server.c
@@ -99,6 +99,83 @@ const char* get_http_date_header()
return buffer_header;
}
+static int is_acme_req(char *req, size_t len) {
+ static const char *A = " - 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ _ abcdefghijklmnopqrstuvwxyz ";
+ int c, i, k;
+
+ // Check first request line. Should be like: GET path HTTP/1.x
+ if (strncmp(req, "GET /.well-known/acme-challenge/", 32))
+ return -1;
+ // Usually (for LE) the "method path" is 32 + 43 = 55 chars. But other
+ // implementations may choose longer pathes. We define PATHMAX = 127 chars
+ // to be prepared for "DoS" attacks (STUN msg size max. is ~ 64K).
+ len =- 21; // min size of trailing headers
+ if (len > 131)
+ len = 131;
+ for (i=32; i < (int) len; i++) {
+ // find the end of the path
+ if (req[i] != ' ')
+ continue;
+ // consider path < 10 chars invalid. Also we wanna see a "trailer".
+ if (i < 42 || strncmp(req + i, " HTTP/1.", 8))
+ return -2;
+ // finally check for allowed chars
+ for (k=32; k < i; k++) {
+ c = req[k];
+ if ((c > 127) || (A[c] == ' '))
+ return -3;
+ }
+ // all checks passed: sufficient for us to answer with a redirect
+ return i;
+ }
+ return -4; // end of path not found
+}
+
+int try_acme_redirect(char *req, size_t len, const char *url,
+ ioa_socket_handle s)
+{
+ static const char *HTML = "
301 Moved Permanently301 Moved Permanently
";
+ char http_response[1024];
+ int plen, rlen;
+
+ if (url == NULL || url[0] == '\0' || req == NULL || s == 0 )
+ return 1;
+ if (len < 64 || len > 512 || (plen = is_acme_req(req, len)) < 33)
+ return 2;
+
+ req[plen] = '\0';
+ snprintf(http_response, sizeof(http_response) - 1,
+ "HTTP/1.1 301 Moved Permanently\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: %ld\r\n"
+ "Connection: close\r\n"
+ "Location: %s%s\r\n"
+ "\r\n%s", strlen(HTML), url, req + 32, HTML);
+
+ rlen = strlen(http_response);
+
+ // Variant A: direkt write, no eventbuf stuff
+ if (write(s->fd, http_response, rlen) == -1) {
+ perror("Sending redirect failed");
+ } else if (((turn_turnserver *)s->session->server)->verbose) {
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "ACME redirect to %s%s\n",
+ url, req + 32);
+ }
+
+ req[plen] = ' ';
+
+ // Variant B: via eventbuf does not send anything for whatever reason
+ /*
+ set_ioa_socket_app_type(s, HTTP_CLIENT_SOCKET);
+ ioa_network_buffer_handle nbh = ioa_network_buffer_allocate(s->e);
+ uint8_t *data = ioa_network_buffer_data(nbh);
+ bcopy(http_response, data, rlen);
+ ioa_network_buffer_set_size(nbh, rlen);
+ send_data_from_ioa_socket_nbh(s, NULL, nbh, TTL_IGNORE, TOS_IGNORE, NULL);
+ */
+
+ return 0;
+}
///////////////////////////////////////////////
static struct headers_list * post_parse(char *data, size_t data_len)
diff --git a/src/apps/relay/mainrelay.c b/src/apps/relay/mainrelay.c
index 2343a1c..e6462d9 100644
--- a/src/apps/relay/mainrelay.c
+++ b/src/apps/relay/mainrelay.c
@@ -1673,25 +1673,25 @@ static void read_config_file(int argc, char **argv, int pass)
if(pass == 0) {
- if (argv) {
- int i = 0;
- for (i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "-c")) {
- if (i < argc - 1) {
- STRCPY(config_file, argv[i + 1]);
- } else {
- TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Wrong usage of -c option\n");
+ if (argv) {
+ int i = 0;
+ for (i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "-c")) {
+ if (i < argc - 1) {
+ STRCPY(config_file, argv[i + 1]);
+ } else {
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Wrong usage of -c option\n");
+ }
+ } else if (!strcmp(argv[i], "-n")) {
+ turn_params.do_not_use_config_file = 1;
+ config_file[0]=0;
+ return;
+ } else if (!strcmp(argv[i], "-h")) {
+ printf("\n%s\n",Usage);
+ exit(0);
+ }
+ }
}
- } else if (!strcmp(argv[i], "-n")) {
- turn_params.do_not_use_config_file = 1;
- config_file[0]=0;
- return;
- } else if (!strcmp(argv[i], "-h")) {
- printf("\n%s\n",Usage);
- exit(0);
- }
- }
- }
}
if (!turn_params.do_not_use_config_file && config_file[0]) {
@@ -1728,7 +1728,7 @@ static void read_config_file(int argc, char **argv, int pass)
STRCPY(sarg, s);
if (parse_arg_string(sarg, &c, &value) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Bad configuration format: %s\n",
- sarg);
+ sarg);
} else if((pass == 0) && (c == 'l')) {
set_logfile(value);
} else if((pass==0) && (c==NO_STDOUT_LOG_OPT)) {
@@ -1742,9 +1742,9 @@ static void read_config_file(int argc, char **argv, int pass)
} else if ((pass==0) && (c==NEW_LOG_TIMESTAMP_FORMAT_OPT)) {
set_turn_log_timestamp_format(value);
} else if((pass == 0) && (c != 'u')) {
- set_option(c, value);
+ set_option(c, value);
} else if((pass > 0) && (c == 'u')) {
- set_option(c, value);
+ set_option(c, value);
}
if (s[slen - 1] == 59) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Check config! The following line ends with semicolon: \"%s\" \n",s);
@@ -1757,7 +1757,7 @@ static void read_config_file(int argc, char **argv, int pass)
} else
TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "WARNING: Cannot find config file: %s. Default and command-line settings will be used.\n",
- config_file);
+ config_file);
if (full_path_to_config_file) {
free(full_path_to_config_file);
@@ -1770,7 +1770,7 @@ static int disconnect_database(void)
{
const turn_dbdriver_t * dbd = get_dbdriver();
if (dbd && dbd->disconnect) {
- dbd->disconnect();
+ dbd->disconnect();
}
return 0;
}
@@ -1801,183 +1801,183 @@ static int adminmain(int argc, char **argv)
while (((c = getopt_long(argc, argv, ADMIN_OPTIONS, uo.u.o, NULL)) != -1)) {
switch (c){
- case 'P':
- if(pwd[0]) {
- char result[257];
- generate_new_enc_password((char*)pwd, result);
- printf("%s\n",result);
- exit(0);
- }
- print_enc_password = 1;
- break;
- case 'E':
- print_enc_aes_password = 1;
- break;
- case 'g':
- ct = TA_SET_REALM_OPTION;
- break;
- case 'G':
- ct = TA_LIST_REALM_OPTIONS;
- break;
- case ADMIN_USER_QUOTA_OPT:
- po.user_quota = (vint)atoi(optarg);
- break;
- case ADMIN_TOTAL_QUOTA_OPT:
- po.total_quota = (vint)atoi(optarg);
- break;
- case ADMIN_MAX_BPS_OPT:
- po.max_bps = (vint)atoi(optarg);
- break;
- case 'O':
- ct = TA_ADD_ORIGIN;
- break;
- case 'R':
- ct = TA_DEL_ORIGIN;
- break;
- case 'I':
- ct = TA_LIST_ORIGINS;
- break;
- case 'o':
- STRCPY(origin,optarg);
- break;
- case 'k':
- ct = TA_PRINT_KEY;
- break;
- case 'a':
- ct = TA_UPDATE_USER;
- break;
- case 'd':
- ct = TA_DELETE_USER;
- break;
- case 'A':
- ct = TA_UPDATE_USER;
- is_admin = 1;
- break;
- case 'D':
- ct = TA_DELETE_USER;
- is_admin = 1;
- break;
- case 'l':
- ct = TA_LIST_USERS;
- break;
- case 'L':
- ct = TA_LIST_USERS;
- is_admin = 1;
- break;
- case 's':
- ct = TA_SET_SECRET;
- STRCPY(secret,optarg);
- break;
- case 'S':
- ct = TA_SHOW_SECRET;
- break;
- case 'X':
- ct = TA_DEL_SECRET;
- if(optarg)
- STRCPY(secret,optarg);
- break;
- case DEL_ALL_AUTH_SECRETS_OPT:
- ct = TA_DEL_SECRET;
- break;
+ case 'P':
+ if(pwd[0]) {
+ char result[257];
+ generate_new_enc_password((char*)pwd, result);
+ printf("%s\n",result);
+ exit(0);
+ }
+ print_enc_password = 1;
+ break;
+ case 'E':
+ print_enc_aes_password = 1;
+ break;
+ case 'g':
+ ct = TA_SET_REALM_OPTION;
+ break;
+ case 'G':
+ ct = TA_LIST_REALM_OPTIONS;
+ break;
+ case ADMIN_USER_QUOTA_OPT:
+ po.user_quota = (vint)atoi(optarg);
+ break;
+ case ADMIN_TOTAL_QUOTA_OPT:
+ po.total_quota = (vint)atoi(optarg);
+ break;
+ case ADMIN_MAX_BPS_OPT:
+ po.max_bps = (vint)atoi(optarg);
+ break;
+ case 'O':
+ ct = TA_ADD_ORIGIN;
+ break;
+ case 'R':
+ ct = TA_DEL_ORIGIN;
+ break;
+ case 'I':
+ ct = TA_LIST_ORIGINS;
+ break;
+ case 'o':
+ STRCPY(origin,optarg);
+ break;
+ case 'k':
+ ct = TA_PRINT_KEY;
+ break;
+ case 'a':
+ ct = TA_UPDATE_USER;
+ break;
+ case 'd':
+ ct = TA_DELETE_USER;
+ break;
+ case 'A':
+ ct = TA_UPDATE_USER;
+ is_admin = 1;
+ break;
+ case 'D':
+ ct = TA_DELETE_USER;
+ is_admin = 1;
+ break;
+ case 'l':
+ ct = TA_LIST_USERS;
+ break;
+ case 'L':
+ ct = TA_LIST_USERS;
+ is_admin = 1;
+ break;
+ case 's':
+ ct = TA_SET_SECRET;
+ STRCPY(secret,optarg);
+ break;
+ case 'S':
+ ct = TA_SHOW_SECRET;
+ break;
+ case 'X':
+ ct = TA_DEL_SECRET;
+ if(optarg)
+ STRCPY(secret,optarg);
+ break;
+ case DEL_ALL_AUTH_SECRETS_OPT:
+ ct = TA_DEL_SECRET;
+ break;
#if !defined(TURN_NO_SQLITE)
- case 'b':
- STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
- turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_SQLITE;
- break;
+ case 'b':
+ STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
+ turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_SQLITE;
+ break;
#endif
#if !defined(TURN_NO_PQ)
- case 'e':
- STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
- turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_PQ;
- break;
+ case 'e':
+ STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
+ turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_PQ;
+ break;
#endif
#if !defined(TURN_NO_MYSQL)
- case 'M':
- STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
- turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL;
- break;
+ case 'M':
+ STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
+ turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL;
+ break;
#endif
#if !defined(TURN_NO_MONGO)
- case 'J':
- STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
- turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MONGO;
- break;
+ case 'J':
+ STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
+ turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MONGO;
+ break;
#endif
#if !defined(TURN_NO_HIREDIS)
- case 'N':
- STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
- turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_REDIS;
- break;
+ case 'N':
+ STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
+ turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_REDIS;
+ break;
#endif
- case 'u':
- STRCPY(user,optarg);
- if(!is_secure_string((uint8_t*)user,1)) {
- TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong user name structure or symbols, choose another name: %s\n",user);
- exit(-1);
- }
- if(SASLprep((uint8_t*)user)<0) {
- TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong user name: %s\n",user);
- exit(-1);
- }
- break;
- case 'r':
- set_default_realm_name(optarg);
- STRCPY(realm,optarg);
- if(SASLprep((uint8_t*)realm)<0) {
- TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong realm: %s\n",realm);
- exit(-1);
- }
- break;
- case 'p':
- STRCPY(pwd,optarg);
- if(SASLprep((uint8_t*)pwd)<0) {
- TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password: %s\n",pwd);
- exit(-1);
- }
- if(print_enc_password) {
- char result[257];
- generate_new_enc_password((char*)pwd, result);
- printf("%s\n",result);
- exit(0);
- }
- if(print_enc_aes_password){
- encrypt_aes_128(pwd, generated_key);
- exit(0);
- }
- break;
- case 'x':
- generate_aes_128_key(optarg, generated_key);
- exit(0);
- break;
- case 'f':
- fptr = fopen((char*)optarg, "r");
- if(fptr == NULL){
- printf("No such file like %s\n", (char*)optarg);
- }
- else{
- fseek (fptr, 0, SEEK_SET);
- rc = fread(generated_key, sizeof(char), 16, fptr);
- if( rc == 0 ){
- TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: Secret-Key file is empty\n",__FUNCTION__);
+ case 'u':
+ STRCPY(user,optarg);
+ if(!is_secure_string((uint8_t*)user,1)) {
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong user name structure or symbols, choose another name: %s\n",user);
+ exit(-1);
+ }
+ if(SASLprep((uint8_t*)user)<0) {
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong user name: %s\n",user);
+ exit(-1);
+ }
+ break;
+ case 'r':
+ set_default_realm_name(optarg);
+ STRCPY(realm,optarg);
+ if(SASLprep((uint8_t*)realm)<0) {
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong realm: %s\n",realm);
+ exit(-1);
+ }
+ break;
+ case 'p':
+ STRCPY(pwd,optarg);
+ if(SASLprep((uint8_t*)pwd)<0) {
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password: %s\n",pwd);
+ exit(-1);
+ }
+ if(print_enc_password) {
+ char result[257];
+ generate_new_enc_password((char*)pwd, result);
+ printf("%s\n",result);
+ exit(0);
+ }
+ if(print_enc_aes_password){
+ encrypt_aes_128(pwd, generated_key);
+ exit(0);
+ }
+ break;
+ case 'x':
+ generate_aes_128_key(optarg, generated_key);
+ exit(0);
+ break;
+ case 'f':
+ fptr = fopen((char*)optarg, "r");
+ if(fptr == NULL){
+ printf("No such file like %s\n", (char*)optarg);
}
else{
- if( rc != 16 ){
- TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: Secret-Key length is not enough\n",__FUNCTION__);
+ fseek (fptr, 0, SEEK_SET);
+ rc = fread(generated_key, sizeof(char), 16, fptr);
+ if( rc == 0 ){
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: Secret-Key file is empty\n",__FUNCTION__);
}
+ else{
+ if( rc != 16 ){
+ TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: Secret-Key length is not enough\n",__FUNCTION__);
+ }
+ }
+ fclose (fptr);
}
- fclose (fptr);
- }
- break;
- case 'v':
- decrypt_aes_128((char*)optarg, generated_key);
- exit(0);
- case 'h':
- printf("\n%s\n", AdminUsage);
- exit(0);
- break;
- default:
- fprintf(stderr,"\n%s\n", AdminUsage);
- exit(-1);
+ break;
+ case 'v':
+ decrypt_aes_128((char*)optarg, generated_key);
+ exit(0);
+ case 'h':
+ printf("\n%s\n", AdminUsage);
+ exit(0);
+ break;
+ default:
+ fprintf(stderr,"\n%s\n", AdminUsage);
+ exit(-1);
}
}
@@ -2021,16 +2021,16 @@ static void print_features(unsigned long mfn)
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n\n==== Show him the instruments, Practical Frost: ====\n\n");
-/*
- Frost stepped forward and opened the polished case with a theatrical
- flourish. It was a masterful piece of craftsmanship. As the lid was
- pulled back, the many trays inside lifted and fanned out, displaying
- Glokta’s tools in all their gruesome glory. There were blades of every
- size and shape, needles curved and straight, bottles of oil and acid,
- nails and screws, clamps and pliers, saws, hammers, chisels. Metal, wood
- and glass glittered in the bright lamplight, all polished to mirror
- brightness and honed to a murderous sharpness.
-*/
+ /*
+ Frost stepped forward and opened the polished case with a theatrical
+ flourish. It was a masterful piece of craftsmanship. As the lid was
+ pulled back, the many trays inside lifted and fanned out, displaying
+ Glokta’s tools in all their gruesome glory. There were blades of every
+ size and shape, needles curved and straight, bottles of oil and acid,
+ nails and screws, clamps and pliers, saws, hammers, chisels. Metal, wood
+ and glass glittered in the bright lamplight, all polished to mirror
+ brightness and honed to a murderous sharpness.
+ */
#if !TLS_SUPPORTED
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "TLS is not supported\n");
diff --git a/src/server/ns_turn_ioalib.h b/src/server/ns_turn_ioalib.h
index da3e7c5..4b9f38a 100644
--- a/src/server/ns_turn_ioalib.h
+++ b/src/server/ns_turn_ioalib.h
@@ -285,6 +285,7 @@ int get_default_protocol_port(const char* scheme, size_t slen);
///////////// HTTP ////////////////////
void handle_http_echo(ioa_socket_handle s);
+int try_acme_redirect(char *req, size_t len, const char *url, ioa_socket_handle s);
///////////// ACME /////////////////////