@@ -119,6 +119,81 @@ conn_is_alive(int fd)
119119 return (1 ); /* Data available: might be stale response */
120120}
121121
122+ int
123+ vwasm_http_addr_is_private (const struct sockaddr * sa )
124+ {
125+ if (sa == NULL )
126+ return (1 );
127+
128+ if (sa -> sa_family == AF_INET ) {
129+ const struct sockaddr_in * sin ;
130+ uint32_t ip ;
131+
132+ sin = (const struct sockaddr_in * )sa ;
133+ ip = ntohl (sin -> sin_addr .s_addr );
134+
135+ /* 127.0.0.0/8 — loopback */
136+ if ((ip >> 24 ) == 127 )
137+ return (1 );
138+ /* 10.0.0.0/8 — RFC1918 */
139+ if ((ip >> 24 ) == 10 )
140+ return (1 );
141+ /* 172.16.0.0/12 — RFC1918 */
142+ if ((ip >> 20 ) == (172 << 4 | 1 ))
143+ return (1 );
144+ /* 192.168.0.0/16 — RFC1918 */
145+ if ((ip >> 16 ) == ((192 << 8 ) | 168 ))
146+ return (1 );
147+ /* 169.254.0.0/16 — link-local */
148+ if ((ip >> 16 ) == ((169 << 8 ) | 254 ))
149+ return (1 );
150+ /* 0.0.0.0/8 — "this" network */
151+ if ((ip >> 24 ) == 0 )
152+ return (1 );
153+ /* 100.64.0.0/10 — shared address space (CGN) */
154+ if ((ip >> 22 ) == (100 << 2 | 1 ))
155+ return (1 );
156+ /* 192.0.0.0/24 — IETF protocol assignments */
157+ if ((ip >> 8 ) == ((192 << 16 ) | 0 ))
158+ return (1 );
159+ /* 198.18.0.0/15 — benchmarking */
160+ if ((ip >> 17 ) == ((198 << 7 ) | 9 ))
161+ return (1 );
162+ /* 240.0.0.0/4 — reserved (includes broadcast) */
163+ if ((ip >> 28 ) == 15 )
164+ return (1 );
165+ } else if (sa -> sa_family == AF_INET6 ) {
166+ const struct sockaddr_in6 * sin6 ;
167+ const uint8_t * b ;
168+
169+ sin6 = (const struct sockaddr_in6 * )sa ;
170+ b = sin6 -> sin6_addr .s6_addr ;
171+
172+ /* ::1/128 — loopback */
173+ if (memcmp (b , "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1" , 16 ) == 0 )
174+ return (1 );
175+ /* ::/128 — unspecified */
176+ if (memcmp (b , "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" , 16 ) == 0 )
177+ return (1 );
178+ /* fc00::/7 — unique local (RFC4193) */
179+ if ((b [0 ] & 0xfe ) == 0xfc )
180+ return (1 );
181+ /* fe80::/10 — link-local */
182+ if (b [0 ] == 0xfe && (b [1 ] & 0xc0 ) == 0x80 )
183+ return (1 );
184+ /* ::ffff:0:0/96 — IPv4-mapped, check inner IPv4 */
185+ if (memcmp (b , "\0\0\0\0\0\0\0\0\0\0\xff\xff" , 12 ) == 0 ) {
186+ struct sockaddr_in inner ;
187+ memset (& inner , 0 , sizeof (inner ));
188+ inner .sin_family = AF_INET ;
189+ memcpy (& inner .sin_addr .s_addr , b + 12 , 4 );
190+ return (vwasm_http_addr_is_private (
191+ (const struct sockaddr * )& inner ));
192+ }
193+ }
194+ return (0 );
195+ }
196+
122197/*
123198 * Connect to host:port with timeout.
124199 */
@@ -538,7 +613,7 @@ vwasm_http_pool_cb_failure(struct vwasm_http_pool *pool,
538613
539614int
540615vwasm_http_pool_acquire (struct vwasm_http_pool * pool ,
541- const char * host , uint16_t port , uint32_t timeout_ms ,
616+ const char * host , uint16_t port , uint32_t timeout_ms , int ssrf_exempt ,
542617 struct vwasm_http_conn * * conn_out )
543618{
544619 struct sockaddr_storage addr ;
@@ -565,6 +640,8 @@ vwasm_http_pool_acquire(struct vwasm_http_pool *pool,
565640 for (i = 0 ; i < pool -> max_conns ; i ++ ) {
566641 struct vwasm_http_conn * c = & pool -> conns [i ];
567642
643+ if (!ssrf_exempt )
644+ continue ;
568645 if (c -> fd < 0 || c -> in_use )
569646 continue ;
570647 if (strcmp (c -> host , host ) != 0 || c -> port != port )
@@ -608,6 +685,9 @@ vwasm_http_pool_acquire(struct vwasm_http_pool *pool,
608685 /* Resolve DNS */
609686 if (vwasm_http_pool_resolve (pool , host , port , & addr , & addrlen ) != 0 )
610687 return (-1 );
688+ if (!ssrf_exempt &&
689+ vwasm_http_addr_is_private ((const struct sockaddr * )& addr ))
690+ return (-1 );
611691
612692 /* Connect with timeout */
613693 fd = connect_with_timeout (& addr , addrlen , timeout_ms );
0 commit comments