Hello,

Thanks for this, it's indeed useful and well-contained for a
contribution.

Samuel

Gianluca Cannata, le mer. 21 janv. 2026 09:31:37 +0100, a ecrit:
> Index: httpfs/http.c
> ===================================================================
> --- httpfs.orig/http.c
> +++ httpfs/http.c
> @@ -34,14 +34,59 @@
>  #include <hurd/hurd_types.h>
>  #include <hurd/netfs.h>
>  
> -/* do a DNS lookup for NAME and store result in *ENT */
> -error_t lookup_host (char *url, struct hostent **ent) 
> +/* do a DNS lookup for HOST and store result in *DEST */
> +error_t lookup_host (const char *host, struct sockaddr_storage *dest, 
> socklen_t *dest_len) 
>  {
> -       if ( (*ent = gethostbyname(url)) == NULL )
> -       {
> -               fprintf(stderr,"wrong host name\n");
> +       struct addrinfo hints;
> +       struct addrinfo *res;
> +       int s;
> +
> +       /* Buffer that holds a clean host, that is a host without square 
> brackets in case of a IPv6 address */
> +       char clean_host[256];

Rather than hard-coding 256, you can use strlen(host)-1. Then you won't
have an ENAMETOOLONG error.

> +       const char *host_ptr = host;

You don't need a separate host_ptr variable. When using clean_host, you
can as well just do host = clean_host.

> +       if (!host || !dest || !dest_len)
>                 return EINVAL;
> +
> +       /* IPv6 syntax transformation: e.g. [2001:db8::1] -> 2001:db8::1
> +        * because getaddrinfo does not accept square brackets, but URLs do.
> +        */
> +       if (host[0] == '[') {
> +               const char *end = strchr (host, ']');

If you have an opening bracket, the closing bracket should be the last
character anyway, so you can as well directly check for ']' at the end,
and return EINVAL otherwise.

> +               if (end) {
> +                       size_t host_len = end - host - 1;
> +                       if (host_len >= sizeof (clean_host)) return 
> ENAMETOOLONG;
> +
> +                       strncpy (clean_host, host + 1, host_len);

Better use memcpy.

> +                       clean_host[host_len] = '\0';
> +                       host_ptr = clean_host;
> +               }
>         }
> +
> +       memset (&hints, 0, sizeof (struct addrinfo));

better use sizeof(hints), which we then know for sure is correct.

> +       hints.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
> +       hints.ai_socktype = SOCK_STREAM; /* TCP */
> +       /* AI_ADDRCONFIG: Asks for AAAA record only if the host has IPv6 
> connectivity.
> +        * AI_V4MAPPED: Maps IPv4 to IPv6 if necessary. */
> +       hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
> +
> +       /* DNS lookup */
> +       s = getaddrinfo (host_ptr, NULL, &hints, &res);
> +       if (s != 0) {
> +               if (debug_flag)
> +                       fprintf (stderr, "DNS lookup failed for %s: %s\n", 
> host_ptr, gai_strerror (s));
> +
> +               return ENOENT;
> +       }
> +
> +       /* TODO: Shall we copy only the first result or iterate through 
> possible multiple results */

Ideally we'd try to connect to each result until one succeeds. But that
will do for now.

> +       if (res != NULL) {
> +               memcpy (dest, res->ai_addr, res->ai_addrlen);
> +               *dest_len = res->ai_addrlen;
> +               dest->ss_family = res->ai_family;

res->ai_addr.sa_family will already have filled dest->ss_family, no need
to fill it again.

> +       }
> +
> +       freeaddrinfo (res);
>         return 0;
>  }
>  
> @@ -52,8 +97,8 @@ error_t open_connection(struct netnode *
>          * head. *HEAD_LEN indicates the header length, for pruning upto that 
> */
>         
>         error_t err;
> -       struct hostent *hptr;
> -       struct sockaddr_in dest;
> +       struct sockaddr_storage server_addr;
> +       socklen_t addr_len;
>         ssize_t written;
>         size_t towrite;
>         char buffer[4096];
> @@ -63,49 +108,39 @@ error_t open_connection(struct netnode *
>         char delimiters0[] = " ";
>         char delimiters1[] = "\n";
>  
> -       bzero(&dest,sizeof(dest));
> -       dest.sin_family = AF_INET;
> -       dest.sin_port = htons (port);
> -
> -       if ( !strcmp(ip_addr,"0.0.0.0") )
> -       {
> -               /* connection is not through a proxy server
> -                * find IP addr. of remote server */
> -               err = lookup_host (node->url, &hptr);
> -               if (err)
> -               {
> -                       fprintf(stderr,"Could not find IP addr 
> %s\n",node->url);
> -                       return err;
> -               }
> -               dest.sin_addr = *(struct in_addr *)hptr->h_addr;
> -       }
> -       else
> -       {
> -               /* connection is through the proxy server
> -                * need not find IP of remote server
> -                * find IP of the proxy server */
> -               if ( inet_aton(ip_addr,&dest.sin_addr) == 0 )
> -               {
> -                       fprintf(stderr,"Invalid IP for proxy\n");
> -                       return -1;
> -               }
> +       /* 1. Target selection.
> +        * If ip_addr (proxy global variable) is set, we use it. 
> +        * Otherwise we use the node URL.
> +        */
> +       const char *target_host = (strcmp (ip_addr, "0.0.0.0") != 0) ? 
> ip_addr : node->url;
> +
> +       /* 2. Agnostic resolution (IPv4/IPv6) */
> +       if ((err = lookup_host (target_host, &server_addr, &addr_len)) != 0) {
> +               fprintf (stderr, "Cannot resolve host: %s\n", target_host);
> +               return err;
> +       }
> +
> +       /* 3. Set of the port. */
> +       if (server_addr.ss_family == AF_INET) {
> +               ((struct sockaddr_in *)&server_addr)->sin_port = htons (port);
> +       } else if (server_addr.ss_family == AF_INET6) {
> +               ((struct sockaddr_in6 *)&server_addr)->sin6_port = htons 
> (port);
>         }
>  
>         if (debug_flag)
> -               fprintf (stderr, "trying to open %s:%d/%s\n", node->url,
> -                               port, node->conn_req);
> +               fprintf (stderr, "Connecting to %s via %s:%d\n", node->url, 
> target_host, port);
>  
> -       *fd = socket (AF_INET, SOCK_STREAM, 0);
> +       /* 4. First connection: HEAD request */
> +       *fd = socket (server_addr.ss_family, SOCK_STREAM, 0);

Ideally, you'd make lookup_host also take more parameters, to be filled
by res->ai_socktype and res->ai_protocol, instead of hardcoding
SOCK_STREAM and 0.

>         if (*fd == -1)
>         {
> -               fprintf(stderr,"Socket creation error\n");
> +               perror ("Socket creation error for HEAD request");
>                 return errno;
>         }
>  
> -       err = connect (*fd, (struct sockaddr *)&dest, sizeof (dest));
> -       if (err == -1)
> -       {
> -               fprintf(stderr,"Cannot connect to remote host\n");
> +       if (connect (*fd, (struct sockaddr *)&server_addr, addr_len) == -1) {
> +               perror ("Connection to remote host failed");
> +               close (*fd);
>                 return errno;
>         }
>  
> @@ -142,21 +177,20 @@ error_t open_connection(struct netnode *
>         
>         close(*fd);
>         
> +       /* 5. Second connection: GET request */
>         /* Send the GET request for the url */
> -       *fd = socket (AF_INET, SOCK_STREAM, 0);
> +       *fd = socket (server_addr.ss_family, SOCK_STREAM, 0);

Ditto

>         if (*fd == -1)
>         {
> -               fprintf(stderr,"Socket creation error\n");
> +               perror ("Socket creation error for GET request");
>                 return errno;
>         }
>  
> -       err = connect (*fd, (struct sockaddr *)&dest, sizeof (dest));
> -       if (err == -1)
> -       {
> -               fprintf(stderr,"Cannot connect to remote host\n");
> +       if (connect (*fd, (struct sockaddr *)&server_addr, addr_len) == -1) {
> +               perror ("Connection to remote host failed");
> +               close (*fd);
>                 return errno;
>         }
> -
>         towrite = strlen (node->comm_buf);
>  
>         /* guard against EINTR failures */
> Index: httpfs/httpfs.h
> ===================================================================
> --- httpfs.orig/httpfs.h
> +++ httpfs/httpfs.h
> @@ -119,8 +119,8 @@ error_t parse(struct netnode *node);
>   * string */
>  void extract(char *string,char *parent);
>  
> -/* do a DNS lookup for NAME and store result in *ENT */
> -error_t lookup_host (char *url, struct hostent **ent);
> +/* do a DNS lookup for HOST and store result in *DEST */
> +error_t lookup_host (const char *url, struct sockaddr_storage *dest, 
> socklen_t *dest_len);
>  
>  /* store the remote socket in *FD and establish the connection and send the 
>   * http GET request */


Reply via email to