Skip to content

IPv6 support for php-fpm (fixes: #55508) #631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 43 additions & 42 deletions sapi/fpm/fpm/fpm_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,6 @@ struct listening_socket_s {

static struct fpm_array_s sockets_list;

static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr) /* {{{ */
{
struct addrinfo *res;
struct addrinfo hints;
int ret;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
ret = getaddrinfo(node, service, &hints, &res);

if (ret != 0) {
zlog(ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n",
node, service ? ":" : "", service ? service : "",
gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : "");
return -1;
}

*addr = *(struct sockaddr_in *) res->ai_addr;
freeaddrinfo(res);
return 0;
}
/* }}} */

enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 };

static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */
Expand Down Expand Up @@ -98,14 +75,23 @@ static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */
}
/* }}} */

static void *fpm_get_in_addr(struct sockaddr *sa) /* {{{ */
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}

return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
/* }}} */

static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op) /* {{{ */
{
if (key == NULL) {
switch (type) {
case FPM_AF_INET : {
struct sockaddr_in *sa_in = (struct sockaddr_in *) sa;
key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp"));
sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port));
key = alloca(INET6_ADDRSTRLEN);
inet_ntop(sa->sa_family, fpm_get_in_addr(sa), key, sizeof key);
break;
}

Expand Down Expand Up @@ -254,11 +240,14 @@ enum fpm_address_domain fpm_sockets_domain_from_address(char *address) /* {{{ */

static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* {{{ */
{
struct sockaddr_in sa_in;
struct addrinfo hints, *servinfo, *p;
char *dup_address = strdup(wp->config->listen_address);
char *port_str = strchr(dup_address, ':');
char *port_str = strrchr(dup_address, ':');
char *addr = NULL;
int addr_len;
int port = 0;
int sock;
int status;

if (port_str) { /* this is host:port pair */
*port_str++ = '\0';
Expand All @@ -274,23 +263,35 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /*
return -1;
}

memset(&sa_in, 0, sizeof(sa_in));

if (addr) {
sa_in.sin_addr.s_addr = inet_addr(addr);
if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */
if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) {
return -1;
}
zlog(ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr));
// strip brackets from address for getaddrinfo
if (addr != NULL) {
addr_len = strlen(addr);
if (addr[0] == '[' && addr[addr_len - 1] == ']') {
addr[addr_len - 1] = '\0';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like replacing ']' by \0 which seems strange to me

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jpauli if the user enters an ipv6 address with the [ip]:port format those [ and ] have to be removed. This line you pointed just deletes the ] in the last char and the next line addr++; deletes the [ in the first char

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup I see now

addr++;
}
} else {
sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
}
sa_in.sin_family = AF_INET;
sa_in.sin_port = htons(port);

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

if ((status = getaddrinfo(addr, port_str, &hints, &servinfo)) != 0) {
zlog(ZLOG_ERROR, "getaddrinfo: %s\n", gai_strerror(status));
return -1;
}

free(dup_address);
return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in));

for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sock = fpm_sockets_get_listening_socket(wp, p->ai_addr, p->ai_addrlen)) != -1) {
break;
}
}

freeaddrinfo(servinfo);

return sock;
}
/* }}} */

Expand Down
6 changes: 0 additions & 6 deletions sapi/fpm/fpm/fpm_sockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,4 @@ static inline int fd_set_blocked(int fd, int blocked) /* {{{ */
}
/* }}} */

#define IPQUAD(sin_addr) \
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[0], \
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[1], \
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[2], \
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[3]

#endif
2 changes: 2 additions & 0 deletions sapi/fpm/php-fpm.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ group = @php_fpm_group@
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
; a specific port;
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses on a
; specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
Expand Down
53 changes: 53 additions & 0 deletions sapi/fpm/tests/003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
--TEST--
FPM: Test IPv6 support
--SKIPIF--
<?php include "skipif.inc"; ?>
--FILE--
<?php

include "include.inc";

$logfile = dirname(__FILE__).'/php-fpm.log.tmp';

$cfg = <<<EOT
[global]
error_log = $logfile
[unconfined]
listen = [::1]:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOT;

$fpm = run_fpm($cfg, $tail);
if (is_resource($fpm)) {
var_dump(fgets($tail));
var_dump(fgets($tail));
$i = 0;
while (($i++ < 30) && !($fp = fsockopen('[::1]', 9000))) {
usleep(10000);
}
if ($fp) {
echo "Done\n";
fclose($fp);
}
proc_terminate($fpm);
stream_get_contents($tail);
fclose($tail);
proc_close($fpm);
}

?>
--EXPECTF--
string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
"
string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
"
Done
--CLEAN--
<?php
$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
@unlink($logfile);
?>