IP-SENDTO with pf=ip4 failed with "trailing garbage"

This commit is contained in:
Gerhard Rieger 2024-07-26 10:14:57 +02:00
parent 602a54420e
commit bd727963a0
4 changed files with 53 additions and 71 deletions

View file

@ -19,8 +19,8 @@ Corrections:
did not work. did not work.
Thanks to Linus Luessing for reporting this bug. Thanks to Linus Luessing for reporting this bug.
Up to version 1.8.0.0 IP-SENDTO and option pf (protocol-family) with IP-SENDTO and option pf (protocol-family) with protocol name (vs.numeric
protocol name (vs.numeric argument) failed with message: argument) failed with message:
E retropts_int(): trailing garbage in numerical arg of option "protocol-family" E retropts_int(): trailing garbage in numerical arg of option "protocol-family"
Test: IP_SENDTO_PF Test: IP_SENDTO_PF

View file

@ -346,7 +346,7 @@ int sockaddr_vm_parse(struct sockaddr_vm *sa, const char *cid_str,
return 0; return 0;
} }
#endif /* WITH_IP4 */ #endif /* WITH_VSOCK */
#if !HAVE_INET_NTOP #if !HAVE_INET_NTOP
/* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */ /* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */

View file

@ -393,16 +393,18 @@ int xiogetaddrinfo(const char *node, const char *service,
ai_flags?ai_flags[0]:0, ai_flags?ai_flags[1]:0, res); ai_flags?ai_flags[0]:0, ai_flags?ai_flags[1]:0, res);
if (service && service[0]=='\0') { if (service && service[0]=='\0') {
Error("xiogetaddrinfo(): empty port and service"); Error("xiogetaddrinfo(): empty port and service");
return EAI_NONAME;
} }
#if LATER #if LATER
#ifdef WITH_VSOCK #ifdef WITH_VSOCK
if (family == AF_VSOCK) { if (family == AF_VSOCK) {
error_num = sockaddr_vm_parse(&sau->vm, node, service); error_num = sockaddr_vm_parse(&sau->vm, node, service);
if (error_num < 0) if (error_num < 0) {
return STAT_NORETRY; errno = EINVAL;
return EAI_SYSTEM;
return STAT_OK; }
return 0;
} }
#endif /* WITH_VSOCK */ #endif /* WITH_VSOCK */
#endif /* LATER */ #endif /* LATER */
@ -457,7 +459,7 @@ int xiogetaddrinfo(const char *node, const char *service,
#if WITH_IP6 #if WITH_IP6
} else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') { } else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') {
if ((numnode = Malloc(nodelen-1)) == NULL) if ((numnode = Malloc(nodelen-1)) == NULL)
return STAT_NORETRY; return EAI_MEMORY;
strncpy(numnode, node+1, nodelen-2); /* ok */ strncpy(numnode, node+1, nodelen-2); /* ok */
numnode[nodelen-2] = '\0'; numnode[nodelen-2] = '\0';
@ -507,25 +509,19 @@ int xiogetaddrinfo(const char *node, const char *service,
freeaddrinfo(*res); freeaddrinfo(*res);
if (numnode) if (numnode)
free(numnode); free(numnode);
return STAT_NORETRY; return EAI_SERVICE;
} }
/* Probably unsupported protocol (e.g. UDP-Lite), fallback to 0 */ /* Probably unsupported protocol (e.g. UDP-Lite), fallback to 0 */
hints.ai_protocol = 0; hints.ai_protocol = 0;
continue; continue;
} }
if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) { if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) {
Error7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
node?node:"NULL", service?service:"NULL",
hints.ai_flags, hints.ai_family,
hints.ai_socktype, hints.ai_protocol,
(error_num == EAI_SYSTEM)?
strerror(errno):gai_strerror(error_num));
if (*res != NULL) if (*res != NULL)
freeaddrinfo(*res); freeaddrinfo(*res);
if (numnode) if (numnode)
free(numnode); free(numnode);
return STAT_RETRYLATER; return error_num;
} }
} while (1); } while (1);
service = NULL; /* do not resolve later again */ service = NULL; /* do not resolve later again */
@ -645,12 +641,13 @@ int xiogetaddrinfo(const char *node, const char *service,
#else #else
Error("no resolver function available"); Error("no resolver function available");
return STAT_NORETRY; errno = ENOSYS;
return EAI_SYSTEM;
#endif #endif
if (numnode) free(numnode); if (numnode) free(numnode);
return STAT_OK; return 0;
} }
void xiofreeaddrinfo(struct addrinfo *res) { void xiofreeaddrinfo(struct addrinfo *res) {
@ -668,11 +665,12 @@ void xiofreeaddrinfo(struct addrinfo *res) {
/* A simple resolver interface that just returns one address, /* A simple resolver interface that just returns one address,
the first found by calling xiogetaddrinfo(). the first found by calling xiogetaddrinfo().
family may be AF_INET, AF_INET6, or AF_UNSPEC; pf may be AF_INET, AF_INET6, or AF_UNSPEC;
Returns -1 when an error occurred or when no result found. on failure logs error message;
returns STAT_OK, STAT_RETRYLATER, STAT_NORETRY
*/ */
int xioresolve(const char *node, const char *service, int xioresolve(const char *node, const char *service,
int family, int socktype, int protocol, int pf, int socktype, int protocol,
union sockaddr_union *addr, socklen_t *addrlen, union sockaddr_union *addr, socklen_t *addrlen,
const int ai_flags[2]) const int ai_flags[2])
{ {
@ -680,28 +678,38 @@ int xioresolve(const char *node, const char *service,
struct addrinfo *aip; struct addrinfo *aip;
int rc; int rc;
rc = xiogetaddrinfo(node, service, family, socktype, protocol, rc = xiogetaddrinfo(node, service, pf, socktype, protocol,
&res, ai_flags); &res, ai_flags);
if (rc != 0) { if (rc == EAI_AGAIN) {
Warn3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, gai_strerror(rc));
xiofreeaddrinfo(res); xiofreeaddrinfo(res);
return -1; return STAT_RETRYLATER;
} else if (rc != 0) {
Error3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf,
(rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
xiofreeaddrinfo(res);
return STAT_NORETRY;
} }
if (res == NULL) { if (res == NULL) {
Warn1("xioresolve(node=\"%s\", ...): No result", node); Error3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, gai_strerror(EAI_NODATA));
xiofreeaddrinfo(res); xiofreeaddrinfo(res);
return -1; return STAT_NORETRY;
} }
if (res->ai_addrlen > *addrlen) { if (res->ai_addrlen > *addrlen) {
Warn3("xioresolve(node=\"%s\", addrlen="F_socklen", ...): "F_socklen" bytes required", node, *addrlen, res->ai_addrlen); Error3("xioresolve(node=\"%s\", addrlen="F_socklen", ...): "F_socklen" bytes required",
node, *addrlen, res->ai_addrlen);
xiofreeaddrinfo(res); xiofreeaddrinfo(res);
return -1; return STAT_NORETRY;
} }
if (res->ai_next != NULL) { if (res->ai_next != NULL) {
Info4("xioresolve(node=\"%s\", service=%s%s%s, ...): More than one address found", node?node:"NULL", service?"\"":"", service?service:"NULL", service?"\"":""); Info4("xioresolve(node=\"%s\", service=%s%s%s, ...): More than one address found", node?node:"NULL", service?"\"":"", service?service:"NULL", service?"\"":"");
} }
aip = res; aip = res;
if (ai_flags != NULL && ai_flags[0] & AI_PASSIVE && family == PF_UNSPEC) { if (ai_flags != NULL && ai_flags[0] & AI_PASSIVE && pf == PF_UNSPEC) {
/* We select the first IPv6 address, if available, /* We select the first IPv6 address, if available,
because this might accept IPv4 connections too */ because this might accept IPv4 connections too */
while (aip != NULL) { while (aip != NULL) {
@ -711,12 +719,22 @@ int xioresolve(const char *node, const char *service,
} }
if (aip == NULL) if (aip == NULL)
aip = res; aip = res;
} else if (pf == PF_UNSPEC && xioparms.preferred_ip != '0') {
int prefip = PF_UNSPEC;
xioinit_ip(&prefip, xioparms.preferred_ip);
while (aip != NULL) {
if (aip->ai_family == prefip)
break;
aip = aip->ai_next;
}
if (aip == NULL)
aip = res;
} }
memcpy(addr, aip->ai_addr, aip->ai_addrlen); memcpy(addr, aip->ai_addr, aip->ai_addrlen);
*addrlen = aip->ai_addrlen; *addrlen = aip->ai_addrlen;
xiofreeaddrinfo(res); xiofreeaddrinfo(res);
return 0; return STAT_OK;
} }
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)

View file

@ -286,21 +286,8 @@ int xioopen_ipdgram_listen(
} }
xioinit_ip(&pf, xioparms.default_ip); xioinit_ip(&pf, xioparms.default_ip);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) {
case '4': pf = PF_INET; break;
case '6': pf = PF_INET6; break;
default: break; /* includes \0 */
}
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto); retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
if (applyopts_single(sfd, opts, PH_INIT) < 0) if (applyopts_single(sfd, opts, PH_INIT) < 0)
@ -460,6 +447,7 @@ int xioopen_udp_datagram(
sfd->para.socket.ip.dosourceport = true; sfd->para.socket.ip.dosourceport = true;
} }
xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
result = result =
@ -535,23 +523,11 @@ int xioopen_udp_recvfrom(
} }
xioinit_ip(&pf, xioparms.default_ip); xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf);
sfd->howtoend = END_NONE; sfd->howtoend = END_NONE;
if (sfd->howtoend == END_UNSPEC) if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_NONE; sfd->howtoend = END_NONE;
retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) {
case '4': pf = PF_INET; break;
case '6': pf = PF_INET6; break;
default: break; /* includes \0 */
}
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
/* Set AI_PASSIVE, except when it is explicitely disabled */ /* Set AI_PASSIVE, except when it is explicitely disabled */
ai_flags2[0] = xfd->stream.para.socket.ip.ai_flags[0]; ai_flags2[0] = xfd->stream.para.socket.ip.ai_flags[0];
@ -626,20 +602,8 @@ int xioopen_udp_recv(
return STAT_NORETRY; return STAT_NORETRY;
} }
xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf); retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) {
case '4': pf = PF_INET; break;
case '6': pf = PF_INET6; break;
default: break; /* includes \0 */
}
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
/* Set AI_PASSIVE, except when it is explicitely disabled */ /* Set AI_PASSIVE, except when it is explicitely disabled */
ai_flags2[0] = xfd->stream.para.socket.ip.ai_flags[0]; ai_flags2[0] = xfd->stream.para.socket.ip.ai_flags[0];