@@ -100,6 +100,95 @@ struct client {
100100 struct client * next ;
101101};
102102
103+ static int target_host_has_forbidden_syntax (const char * host )
104+ {
105+ struct in_addr a4 ;
106+ struct in6_addr a6 ;
107+ size_t i ;
108+
109+ if (!host || * host == '\0' )
110+ return 1 ;
111+ if (strchr (host , '@' ) || strchr (host , '/' ) || strchr (host , '\\' ) ||
112+ strchr (host , '?' ) || strchr (host , '#' ) || strchr (host , '%' ))
113+ return 1 ;
114+ for (i = 0 ; host [i ] != '\0' ; i ++ ) {
115+ if (isspace ((unsigned char )host [i ]))
116+ return 1 ;
117+ }
118+ if (strchr (host , ':' ) != NULL )
119+ return inet_pton (AF_INET6 , host , & a6 ) != 1 ;
120+ if (inet_pton (AF_INET , host , & a4 ) == 1 )
121+ return 0 ;
122+ for (i = 0 ; host [i ] != '\0' ; i ++ ) {
123+ unsigned char ch = (unsigned char )host [i ];
124+ if (!(isalnum (ch ) || ch == '.' || ch == '-' ))
125+ return 1 ;
126+ }
127+ return 0 ;
128+ }
129+
130+ static int sockaddr_is_public (const struct sockaddr * sa )
131+ {
132+ if (sa -> sa_family == AF_INET ) {
133+ const struct sockaddr_in * sin = (const struct sockaddr_in * )sa ;
134+ uint32_t ip = ntohl (sin -> sin_addr .s_addr );
135+
136+ if ((ip >> 24 ) == 10 || (ip >> 24 ) == 127 || (ip >> 24 ) == 0 )
137+ return 0 ;
138+ if ((ip & 0xFFF00000U ) == 0xAC100000U )
139+ return 0 ;
140+ if ((ip & 0xFFFF0000U ) == 0xC0A80000U )
141+ return 0 ;
142+ if ((ip & 0xFFFF0000U ) == 0xA9FE0000U )
143+ return 0 ;
144+ if ((ip & 0xF0000000U ) == 0xE0000000U )
145+ return 0 ;
146+ return 1 ;
147+ }
148+ if (sa -> sa_family == AF_INET6 ) {
149+ const struct sockaddr_in6 * sin6 = (const struct sockaddr_in6 * )sa ;
150+ const uint8_t * ip = sin6 -> sin6_addr .s6_addr ;
151+
152+ if (IN6_IS_ADDR_LOOPBACK (& sin6 -> sin6_addr ) ||
153+ IN6_IS_ADDR_UNSPECIFIED (& sin6 -> sin6_addr ) ||
154+ IN6_IS_ADDR_MULTICAST (& sin6 -> sin6_addr ))
155+ return 0 ;
156+ if ((ip [0 ] & 0xFE ) == 0xFC )
157+ return 0 ;
158+ if (ip [0 ] == 0xFE && (ip [1 ] & 0xC0 ) == 0x80 )
159+ return 0 ;
160+ return 1 ;
161+ }
162+ return 0 ;
163+ }
164+
165+ static int target_is_allowed (const char * host , const char * port , const char * path )
166+ {
167+ struct addrinfo hints , * res = NULL , * rp ;
168+ int allowed = 0 ;
169+
170+ if (!path || path [0 ] != '/' || target_host_has_forbidden_syntax (host ))
171+ return 0 ;
172+ if (strcmp (port , "443" ) != 0 )
173+ return 0 ;
174+
175+ memset (& hints , 0 , sizeof (hints ));
176+ hints .ai_family = AF_UNSPEC ;
177+ hints .ai_socktype = SOCK_STREAM ;
178+ if (getaddrinfo (host , port , & hints , & res ) != 0 )
179+ return 0 ;
180+
181+ allowed = 1 ;
182+ for (rp = res ; rp ; rp = rp -> ai_next ) {
183+ if (!sockaddr_is_public (rp -> ai_addr )) {
184+ allowed = 0 ;
185+ break ;
186+ }
187+ }
188+ freeaddrinfo (res );
189+ return allowed ;
190+ }
191+
103192static int lfd = -1 ;
104193static WOLFSSL_CTX * srv_ctx = NULL ;
105194static WOLFSSL_CTX * cli_ctx = NULL ;
@@ -735,6 +824,8 @@ static int forward_to_dynamic_target(struct req *req, uint8_t *out, uint32_t *ou
735824 return -1 ;
736825 if (parse_url (full , & tc .up ) != 0 )
737826 return -1 ;
827+ if (!target_is_allowed (tc .up .host , tc .up .port , tc .up .path ))
828+ return -1 ;
738829 tc .fd = -1 ;
739830
740831 if (forward_to_upstream (& tc , req , "application/oblivious-dns-message" , out , out_len ) != 0 ) {
@@ -821,6 +912,11 @@ static int in_header_cb(nghttp2_session *session,
821912 if (frame -> hd .type != NGHTTP2_HEADERS || frame -> headers .cat != NGHTTP2_HCAT_REQUEST )
822913 return 0 ;
823914
915+ if (req -> stream_id != 0 && frame -> hd .stream_id != (int32_t )req -> stream_id ) {
916+ nghttp2_submit_rst_stream (session , NGHTTP2_FLAG_NONE ,
917+ frame -> hd .stream_id , NGHTTP2_REFUSED_STREAM );
918+ return 0 ;
919+ }
824920 if (frame -> hd .stream_id != (int32_t )req -> stream_id )
825921 req -> stream_id = frame -> hd .stream_id ;
826922
@@ -944,18 +1040,21 @@ static int in_frame_recv_cb(nghttp2_session *session,
9441040 }
9451041
9461042 nghttp2_session_send (session );
947- free (req -> resp );
948- memset (req , 0 , sizeof (* req ));
9491043 return 0 ;
9501044}
9511045
9521046static int in_stream_close_cb (nghttp2_session * session , int32_t stream_id ,
9531047 uint32_t error_code , void * user_data )
9541048{
1049+ struct client * cl = (struct client * )user_data ;
1050+ struct req * req = cl ? & cl -> req : NULL ;
1051+
9551052 (void )session ;
956- (void )stream_id ;
9571053 (void )error_code ;
958- (void )user_data ;
1054+ if (req && req -> stream_id == (uint32_t )stream_id ) {
1055+ free (req -> resp );
1056+ memset (req , 0 , sizeof (* req ));
1057+ }
9591058 return 0 ;
9601059}
9611060
@@ -982,7 +1081,7 @@ static void client_read(int fd, short revents, void *arg)
9821081 }
9831082
9841083 nghttp2_session_callbacks * cbs = NULL ;
985- nghttp2_settings_entry iv [1 ] = {{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS , 100 }};
1084+ nghttp2_settings_entry iv [1 ] = {{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS , 1 }};
9861085
9871086 if (nghttp2_session_callbacks_new (& cbs ) != 0 ) {
9881087 free_client (cl );
0 commit comments