{"thread":{"id":"65610","subject":"[PATCH] daemon: fix network address handling bugs","startedAt":"2026-05-09T01:48:14Z","lastAt":"2026-05-11T07:54:55Z","messageCount":2,"participants":["Sebastien Tardif via GitGitGadget","Patrick Steinhardt"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"542935","messageId":"pull.2299.git.git.1778291290159.gitgitgadget@gmail.com","threadId":"65610","inReplyTo":null,"subject":"[PATCH] daemon: fix network address handling bugs","fromName":"Sebastien Tardif via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-05-09T01:48:10Z","receivedAt":"2026-05-09T01:48:14Z","isPatch":true,"body":"From: Sebastien Tardif <sebtardif@ncf.ca>\n\nFix three related issues in daemon.c's network address handling:\n\nlookup_hostname() calls getaddrinfo() with AF_UNSPEC hints, so it may\nreturn IPv6 results. However, the code unconditionally casts ai_addr to\nsockaddr_in and passes AF_INET to inet_ntop(). On IPv6-only hosts, this\nreads from the wrong struct offset, producing garbage IP addresses. Fix\nby checking ai_family and handling both AF_INET and AF_INET6.\n\nip2str() passes the sockaddr struct size (ai_addrlen) as the output\nbuffer size argument to inet_ntop(). For IPv6, sizeof(sockaddr_in6) is\n28 bytes but INET6_ADDRSTRLEN is 46, so long IPv6 addresses are silently\ntruncated. Fix by passing sizeof(ip) instead, and drop the now-unused\nlen parameter.\n\nexecute() logs \"Connection from %s:%s\" using REMOTE_ADDR and\nREMOTE_PORT environment variables, but only checks REMOTE_ADDR for NULL.\nIf REMOTE_PORT is unset, NULL is passed to printf's %s, which is\nundefined behavior. Fix by using a fallback string.\n\nSigned-off-by: Sebastien Tardif <sebtardif@ncf.ca>\n---\n    daemon: fix network address handling bugs\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2299%2FSebTardif%2Ffix%2Fdaemon-ipv6-and-null-port-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2299/SebTardif/fix/daemon-ipv6-and-null-port-v1\nPull-Request: https://github.com/git/git/pull/2299\n\n daemon.c | 31 +++++++++++++++++++------------\n 1 file changed, 19 insertions(+), 12 deletions(-)\n\ndiff --git a/daemon.c b/daemon.c\nindex 0a7b1aae44..84a5e38f92 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -674,10 +674,17 @@ static void lookup_hostname(struct hostinfo *hi)\n \n \t\tgai = getaddrinfo(hi->hostname.buf, NULL, &hints, &ai);\n \t\tif (!gai) {\n-\t\t\tstruct sockaddr_in *sin_addr = (void *)ai->ai_addr;\n-\n-\t\t\tinet_ntop(AF_INET, &sin_addr->sin_addr,\n-\t\t\t\t  addrbuf, sizeof(addrbuf));\n+\t\t\tif (ai->ai_family == AF_INET) {\n+\t\t\t\tstruct sockaddr_in *sa =\n+\t\t\t\t\t(struct sockaddr_in *)ai->ai_addr;\n+\t\t\t\tinet_ntop(AF_INET, &sa->sin_addr,\n+\t\t\t\t\t  addrbuf, sizeof(addrbuf));\n+\t\t\t} else if (ai->ai_family == AF_INET6) {\n+\t\t\t\tstruct sockaddr_in6 *sa6 =\n+\t\t\t\t\t(struct sockaddr_in6 *)ai->ai_addr;\n+\t\t\t\tinet_ntop(AF_INET6, &sa6->sin6_addr,\n+\t\t\t\t\t  addrbuf, sizeof(addrbuf));\n+\t\t\t}\n \t\t\tstrbuf_addstr(&hi->ip_address, addrbuf);\n \n \t\t\tif (ai->ai_canonname)\n@@ -742,7 +749,7 @@ static int execute(void)\n \tstruct strvec env = STRVEC_INIT;\n \n \tif (addr)\n-\t\tloginfo(\"Connection from %s:%s\", addr, port);\n+\t\tloginfo(\"Connection from %s:%s\", addr, port ? port : \"?\");\n \n \tset_keep_alive(0);\n \talarm(init_timeout ? init_timeout : timeout);\n@@ -936,7 +943,7 @@ struct socketlist {\n \tsize_t alloc;\n };\n \n-static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)\n+static const char *ip2str(int family, struct sockaddr *sin)\n {\n #ifdef NO_IPV6\n \tstatic char ip[INET_ADDRSTRLEN];\n@@ -947,11 +954,11 @@ static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)\n \tswitch (family) {\n #ifndef NO_IPV6\n \tcase AF_INET6:\n-\t\tinet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len);\n+\t\tinet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, sizeof(ip));\n \t\tbreak;\n #endif\n \tcase AF_INET:\n-\t\tinet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len);\n+\t\tinet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, sizeof(ip));\n \t\tbreak;\n \tdefault:\n \t\txsnprintf(ip, sizeof(ip), \"<unknown>\");\n@@ -1008,14 +1015,14 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis\n \n \t\tif (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {\n \t\t\tlogerror(\"Could not bind to %s: %s\",\n-\t\t\t\t ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),\n+\t\t\t\t ip2str(ai->ai_family, ai->ai_addr),\n \t\t\t\t strerror(errno));\n \t\t\tclose(sockfd);\n \t\t\tcontinue;\t/* not fatal */\n \t\t}\n \t\tif (listen(sockfd, 5) < 0) {\n \t\t\tlogerror(\"Could not listen to %s: %s\",\n-\t\t\t\t ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen),\n+\t\t\t\t ip2str(ai->ai_family, ai->ai_addr),\n \t\t\t\t strerror(errno));\n \t\t\tclose(sockfd);\n \t\t\tcontinue;\t/* not fatal */\n@@ -1069,7 +1076,7 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis\n \n \tif ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {\n \t\tlogerror(\"Could not bind to %s: %s\",\n-\t\t\t ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),\n+\t\t\t ip2str(AF_INET, (struct sockaddr *)&sin),\n \t\t\t strerror(errno));\n \t\tclose(sockfd);\n \t\treturn 0;\n@@ -1077,7 +1084,7 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis\n \n \tif (listen(sockfd, 5) < 0) {\n \t\tlogerror(\"Could not listen to %s: %s\",\n-\t\t\t ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),\n+\t\t\t ip2str(AF_INET, (struct sockaddr *)&sin),\n \t\t\t strerror(errno));\n \t\tclose(sockfd);\n \t\treturn 0;\n\nbase-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0\n-- \ngitgitgadget\n"},{"id":"543028","messageId":"agGLRC1ziF5F8Okh@pks.im","threadId":"65610","inReplyTo":"pull.2299.git.git.1778291290159.gitgitgadget@gmail.com","subject":"Re: [PATCH] daemon: fix network address handling bugs","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-05-11T07:54:44Z","receivedAt":"2026-05-11T07:54:55Z","isPatch":true,"body":"On Sat, May 09, 2026 at 01:48:10AM +0000, Sebastien Tardif via GitGitGadget wrote:\n> From: Sebastien Tardif <sebtardif@ncf.ca>\n> \n> Fix three related issues in daemon.c's network address handling:\n\nThis is a good indicator that this patch should be split up into three\npatches, where each patch addresses one of the issues.\n\n> diff --git a/daemon.c b/daemon.c\n> index 0a7b1aae44..84a5e38f92 100644\n> --- a/daemon.c\n> +++ b/daemon.c\n> @@ -674,10 +674,17 @@ static void lookup_hostname(struct hostinfo *hi)\n>  \n>  \t\tgai = getaddrinfo(hi->hostname.buf, NULL, &hints, &ai);\n>  \t\tif (!gai) {\n> -\t\t\tstruct sockaddr_in *sin_addr = (void *)ai->ai_addr;\n> -\n> -\t\t\tinet_ntop(AF_INET, &sin_addr->sin_addr,\n> -\t\t\t\t  addrbuf, sizeof(addrbuf));\n> +\t\t\tif (ai->ai_family == AF_INET) {\n> +\t\t\t\tstruct sockaddr_in *sa =\n> +\t\t\t\t\t(struct sockaddr_in *)ai->ai_addr;\n> +\t\t\t\tinet_ntop(AF_INET, &sa->sin_addr,\n> +\t\t\t\t\t  addrbuf, sizeof(addrbuf));\n> +\t\t\t} else if (ai->ai_family == AF_INET6) {\n> +\t\t\t\tstruct sockaddr_in6 *sa6 =\n> +\t\t\t\t\t(struct sockaddr_in6 *)ai->ai_addr;\n> +\t\t\t\tinet_ntop(AF_INET6, &sa6->sin6_addr,\n> +\t\t\t\t\t  addrbuf, sizeof(addrbuf));\n> +\t\t\t}\n>  \t\t\tstrbuf_addstr(&hi->ip_address, addrbuf);\n>  \n>  \t\t\tif (ai->ai_canonname)\n\nWe could deduplicate the logic by assigning the address pointer to a\nlocal field first:\n\n    gai = getaddrinfo(hi->hostname.buf, NULL, &hints, &ai);\n    if (!gai) {\n        struct sockaddr_in *sin_addr = (void *)ai->ai_addr;\n        void *addr;\n\n        if (ai->ai_family == AF_INET) {\n            struct sockaddr_in *sa = ai->ai_addr;\n            addr = sa->sin_addr;\n        } else if (ai->ai_family == AF_INET6) {\n            struct sockaddr_in6 *sa6 = ai->ai_addr;\n            addr = sa->sin6_addr;\n        } else {\n            die(\"unexpected address info family\");\n        }\n\n        inet_ntop(ai->ai_family, addr, addrbuf, sizeof(addrbuf));\n        strbuf_addstr(&hi->ip_address, addrbuf);\n\n> @@ -742,7 +749,7 @@ static int execute(void)\n>  \tstruct strvec env = STRVEC_INIT;\n>  \n>  \tif (addr)\n> -\t\tloginfo(\"Connection from %s:%s\", addr, port);\n> +\t\tloginfo(\"Connection from %s:%s\", addr, port ? port : \"?\");\n\nHm. It shouldn't ever happen that either of these is unset as far as I\nknow. But it's weird indeed that we check for one of them to exist, but\nnot for the other.\n\n> @@ -936,7 +943,7 @@ struct socketlist {\n>  \tsize_t alloc;\n>  };\n>  \n> -static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)\n> +static const char *ip2str(int family, struct sockaddr *sin)\n>  {\n>  #ifdef NO_IPV6\n>  \tstatic char ip[INET_ADDRSTRLEN];\n> @@ -947,11 +954,11 @@ static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)\n>  \tswitch (family) {\n>  #ifndef NO_IPV6\n>  \tcase AF_INET6:\n> -\t\tinet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len);\n> +\t\tinet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, sizeof(ip));\n>  \t\tbreak;\n>  #endif\n>  \tcase AF_INET:\n> -\t\tinet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len);\n> +\t\tinet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, sizeof(ip));\n>  \t\tbreak;\n>  \tdefault:\n>  \t\txsnprintf(ip, sizeof(ip), \"<unknown>\");\n\nRight, the last parameter of inet_ntop(3p) declares the size of the\noutput buffer, not of the input address.\n\nThanks!\n\nPatrick\n"}]}