瀏覽代碼

support of --acme-redirect <URL>

Jens Elkner 5 年之前
父節點
當前提交
12c7d19a47
共有 3 個文件被更改,包括 275 次插入197 次删除
  1. 77 0
      src/apps/relay/http_server.c
  2. 197 197
      src/apps/relay/mainrelay.c
  3. 1 0
      src/server/ns_turn_ioalib.h

+ 77 - 0
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 = "<html><head><title>301 Moved Permanently</title></head><body><h1>301 Moved Permanently</h1></body></html>";
+	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)

+ 197 - 197
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;
-#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 '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{
-					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");

+ 1 - 0
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 /////////////////////