Corrected handling of IP_RECVERR

This commit is contained in:
Gerhard Rieger 2021-10-28 21:21:07 +02:00
parent bc32acb5fe
commit d84c22be7a
6 changed files with 177 additions and 28 deletions

View file

@ -50,6 +50,10 @@ Corrections:
Print a message when readbytes option causes EOF
The ip-recverr option had no effect. Corrected and improved its
handling of ancilliary messages, so it is able to analyze ICMP error
packets (Linux only?)
Testing:
Prevent the TIMESTAMP tests from sporadically failing due do seconds
overflow

35
filan.c
View file

@ -35,6 +35,7 @@ bool filan_rawoutput;
int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile);
int tcpan(int fd, FILE *outfile);
int tcpan2(int fd, FILE *outfile);
const char *getfiletypestring(int st_mode);
static int printtime(FILE *outfile, time_t time);
@ -895,10 +896,44 @@ int tcpan(int fd, FILE *outfile) {
sockoptan(fd, optname, SOL_TCP, outfile);
++optname;
}
tcpan2(fd, outfile);
return 0;
}
#endif /* WITH_TCP */
#if WITH_TCP
int tcpan2(int fd, FILE *outfile) {
struct tcp_info tcpinfo;
socklen_t tcpinfolen = sizeof(tcpinfo);
int result;
result = Getsockopt(fd, SOL_TCP, TCP_INFO, &tcpinfo, &tcpinfolen);
if (result < 0) {
Debug4("getsockopt(%d, SOL_TCP, TCP_INFO, %p, {"F_socklen"}): %s",
fd, &tcpinfo, sizeof(tcpinfo), strerror(errno));
return -1;
}
fprintf(outfile, "%s={%u}\t", "TCPI_STATE", tcpinfo.tcpi_state);
#if 0 /* on BSD these components are prefixed with __ - I get tired... */
fprintf(outfile, "%s={%u}\t", "TCPI_CA_STATE", tcpinfo.tcpi_ca_state);
fprintf(outfile, "%s={%u}\t", "TCPI_RETRANSMITS", tcpinfo.tcpi_retransmits);
fprintf(outfile, "%s={%u}\t", "TCPI_PROBES", tcpinfo.tcpi_probes);
fprintf(outfile, "%s={%u}\t", "TCPI_BACKOFF", tcpinfo.tcpi_backoff);
#endif
fprintf(outfile, "%s={%u}\t", "TCPI_OPTIONS", tcpinfo.tcpi_options);
fprintf(outfile, "%s={%u}\t", "TCPI_SND_WSCALE", tcpinfo.tcpi_snd_wscale);
fprintf(outfile, "%s={%u}\t", "TCPI_RCV_WSCALE", tcpinfo.tcpi_rcv_wscale);
//fprintf(outfile, "%s={%u}\t", "TCPI_DELIVERY_RATE_APP_LIMITED", tcpinfo.tcpi_delivery_rate_app_limited);
//fprintf(outfile, "%s={%u}\t", "TCPI_FASTOPEN_CLIENT_FAIL", tcpinfo.tcpi_fastopen_client_fail);
// fprintf(outfile, "%s={%u}\t", "TCPI_", tcpinfo.tcpi_);
return 0;
}
#endif /* WITH_TCP */
#if _WITH_SOCKET
int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) {

View file

@ -464,16 +464,16 @@ int xiogetaddrinfo(const char *node, const char *service,
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
/* converts the ancillary message in *cmsg into a form useable for further
/* Converts the ancillary message in *cmsg into a form useable for further
processing. knows the specifics of common message types.
these are valid for IPv4 and IPv6
returns the number of resulting syntax elements in *num
returns a sequence of \0 terminated type strings in *typbuff
returns a sequence of \0 terminated name strings in *nambuff
returns a sequence of \0 terminated value strings in *valbuff
the respective len parameters specify the available space in the buffers
returns STAT_OK on success
returns STAT_WARNING if a buffer was too short and data truncated.
These are valid for IPv4 and IPv6
Returns the number of resulting syntax elements in *num
Returns a sequence of \0 terminated type strings in *typbuff
Returns a sequence of \0 terminated name strings in *nambuff
Returns a sequence of \0 terminated value strings in *valbuff
The respective len parameters specify the available space in the buffers
Returns STAT_OK on success
Returns STAT_WARNING if a buffer was too short and data truncated.
*/
int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
char *typbuff, int typlen,
@ -519,14 +519,31 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
'\0',
inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr),
scratch3, sizeof(scratch3)));
Notice3("Ancillary message: interface \"%s\", locaddr=%s, dstaddr=%s",
xiogetifname(pktinfo->ipi_ifindex, scratch1, -1),
#if HAVE_PKTINFO_IPI_SPEC_DST
inet4addr_info(ntohl(pktinfo->ipi_spec_dst.s_addr),
scratch2, sizeof(scratch2)),
#else
"",
#endif
inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr),
scratch3, sizeof(scratch3)));
}
return STAT_OK;
#endif /* defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO */
#endif /* WITH_IP4 */
#if defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR
case IP_RECVERR: {
struct sock_extended_err *err =
(struct sock_extended_err *)CMSG_DATA(cmsg);
struct xio_extended_err {
struct sock_extended_err see;
__u32 data0;
__u32 data1;
__u32 data2;
__u32 data3;
} ;
struct xio_extended_err *err =
(struct xio_extended_err *)CMSG_DATA(cmsg);
*num = 6;
typbuff[0] = '\0'; strncat(typbuff, "IP_RECVERR", typlen-1);
snprintf(nambuff, namlen, "%s%c%s%c%s%c%s%c%s%c%s",
@ -537,8 +554,33 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
"IP_RECVERR_TYPE", '\0', "IP_RECVERR_CODE", '\0',
"IP_RECVERR_INFO", '\0', "IP_RECVERR_DATA");
snprintf(valbuff, vallen, "%u%c%u%c%u%c%u%c%u%c%u",
err->ee_errno, '\0', err->ee_origin, '\0', err->ee_type, '\0',
err->ee_code, '\0', err->ee_info, '\0', err->ee_data);
err->see.ee_errno, '\0', err->see.ee_origin, '\0', err->see.ee_type, '\0',
err->see.ee_code, '\0', err->see.ee_info, '\0', err->see.ee_data);
/* semantic part */
switch (err->see.ee_origin) {
char addrbuff[40];
#if WITH_IP4
case SO_EE_ORIGIN_ICMP:
if (1) {
inet4addr_info(ntohl(err->data1), addrbuff, sizeof(addrbuff));
Notice6("received ICMP from %s, type %d, code %d, info %d, data %d, resulting in errno %d",
addrbuff, err->see.ee_type, err->see.ee_code, err->see.ee_info, err->see.ee_data, err->see.ee_errno);
}
break;
#endif /* WITH_IP4 */
#if WITH_IP6
case SO_EE_ORIGIN_ICMP6:
if (1) {
Notice5("received ICMP type %d, code %d, info %d, data %d, resulting in errno %d",
err->see.ee_type, err->see.ee_code, err->see.ee_info, err->see.ee_data, err->see.ee_errno);
}
break;
#endif /* WITH_IP6 */
default:
Notice6("received error message origin %d, type %d, code %d, info %d, data %d, generating errno %d",
err->see.ee_origin, err->see.ee_type, err->see.ee_code, err->see.ee_info, err->see.ee_data, err->see.ee_errno);
break;
}
return STAT_OK;
}
#endif /* defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR */
@ -553,6 +595,7 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
valbuff[0] = '\0';
strncat(valbuff,
xiosubstr(scratch1, sadl->sdl_data, 0, sadl->sdl_nlen), vallen-1);
Notice1("IP_RECVIF: %s", valbuff);
return STAT_OK;
}
#endif /* defined(IP_RECVIF) */
@ -564,6 +607,7 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
nambuff[0] = '\0'; strncat(nambuff, "dstaddr", namlen-1);
envbuff[0] = '\0'; strncat(envbuff, "IP_DSTADDR", envlen-1);
inet4addr_info(ntohl(*(uint32_t *)CMSG_DATA(cmsg)), valbuff, vallen);
Notice1("IP_RECVDSTADDR: %s", valbuff);
return STAT_OK;
#endif
#endif /* WITH_IP4 */
@ -571,9 +615,12 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
#ifdef IP_RECVOPTS
case IP_RECVOPTS:
#endif
cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgctr = -1; break;
cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgctr = -1;
/*!!!*/
break;
case IP_TOS:
cmsgtype = "IP_TOS"; cmsgname = "tos"; cmsgctr = msglen; break;
cmsgtype = "IP_TOS"; cmsgname = "tos"; cmsgctr = msglen;
break;
case IP_TTL: /* Linux */
#ifdef IP_RECVTTL
case IP_RECVTTL: /* FreeBSD */
@ -581,7 +628,7 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
cmsgtype = "IP_TTL"; cmsgname = "ttl"; cmsgctr = msglen; break;
}
/* when we come here we provide a single parameter
with type in cmsgtype, name in cmsgname, value length in msglen */
with name in cmsgname, value length in msglen */
*num = 1;
if (strlen(cmsgtype) >= typlen) rc = STAT_WARNING;
typbuff[0] = '\0'; strncat(typbuff, cmsgtype, typlen-1);
@ -595,9 +642,13 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
}
switch (cmsgctr) {
case sizeof(char):
snprintf(valbuff, vallen, "%u", *(unsigned char *)CMSG_DATA(cmsg)); break;
snprintf(valbuff, vallen, "%u", *(unsigned char *)CMSG_DATA(cmsg));
Notice2("Ancillary message: %s=%u", cmsgname, *(unsigned char *)CMSG_DATA(cmsg));
break;
case sizeof(int):
snprintf(valbuff, vallen, "%u", (*(unsigned int *)CMSG_DATA(cmsg))); break;
snprintf(valbuff, vallen, "%u", (*(unsigned int *)CMSG_DATA(cmsg)));
Notice2("Ancillary message: %s=%u", cmsgname, *(unsigned int *)CMSG_DATA(cmsg));
break;
case 0:
xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0); break;
default: break;

View file

@ -693,6 +693,49 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
#endif /* WITH_GENERICSOCKET */
int xiogetpacketinfo(int fd)
{
#if defined(MSG_ERRQUEUE)
int _errno = errno;
char peername[256];
union sockaddr_union _peername;
/* union sockaddr_union _sockname; */
union sockaddr_union *pa = &_peername; /* peer address */
/* union sockaddr_union *la = &_sockname; */ /* local address */
socklen_t palen = sizeof(_peername); /* peer address size */
char ctrlbuff[1024]; /* ancillary messages */
struct msghdr msgh = {0};
msgh.msg_name = pa;
msgh.msg_namelen = palen;
#if HAVE_STRUCT_MSGHDR_MSGCONTROL
msgh.msg_control = ctrlbuff;
#endif
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(fd,
&msgh,
MSG_ERRQUEUE
#ifdef MSG_TRUNC
|MSG_TRUNC
#endif
) >= 0
) {
palen = msgh.msg_namelen;
Notice1("receiving packet from %s"/*"src"*/,
sockaddr_info(&pa->soa, palen, peername, sizeof(peername))/*,
sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
xiodopacketinfo(&msgh, true, true);
}
errno = _errno;
#endif /* defined(MSG_ERRQUEUE) */
return 0;
}
/* a subroutine that is common to all socket addresses that want to connect
to a peer address.
@ -919,6 +962,10 @@ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
errno = _errno;
return -1;
} else {
/* try to find details about error, especially from ICMP */
xiogetpacketinfo(xfd->fd);
/* continue mainstream */
Msg4(level, "connect(%d, %s, "F_Zd"): %s",
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno));
@ -1408,7 +1455,13 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(xfd->fd, &msgh) < 0) {
if (xiogetpacketsrc(xfd->fd,
&msgh,
MSG_PEEK
#ifdef MSG_TRUNC
|MSG_TRUNC
#endif
) < 0) {
return STAT_RETRYLATER;
}
palen = msgh.msg_namelen;
@ -1626,7 +1679,7 @@ int retropt_socket_pf(struct opt *opts, int *pf) {
/* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
the arriving packet. in msgh the msg_name pointer must refer to an (empty)
sockaddr storage. */
int xiogetpacketsrc(int fd, struct msghdr *msgh) {
int xiogetpacketsrc(int fd, struct msghdr *msgh, int flags) {
char peekbuff[1];
#if HAVE_STRUCT_IOVEC
struct iovec iovec;
@ -1641,11 +1694,7 @@ int xiogetpacketsrc(int fd, struct msghdr *msgh) {
#if HAVE_STRUCT_MSGHDR_MSGFLAGS
msgh->msg_flags = 0;
#endif
if (Recvmsg(fd, msgh, MSG_PEEK
#ifdef MSG_TRUNC
|MSG_TRUNC
#endif
) < 0) {
if (Recvmsg(fd, msgh, flags) < 0) {
Warn1("recvmsg(): %s", strerror(errno));
return STAT_RETRYLATER;
}

View file

@ -116,7 +116,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags,
extern
int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv);
extern
int xiogetpacketsrc(int fd, struct msghdr *msgh);
int xiogetpacketsrc(int fd, struct msghdr *msgh, int flags);
extern
int xiocheckpeer(xiosingle_t *xfd,
union sockaddr_union *pa, union sockaddr_union *la);

View file

@ -128,7 +128,12 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
if (xiogetpacketsrc(pipe->fd, &msgh,
MSG_PEEK
#ifdef MSG_TRUNC
|MSG_TRUNC
#endif
) < 0) {
return -1;
}
do {
@ -325,7 +330,12 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
msgh.msg_controllen = sizeof(ctrlbuff);
#endif
if (xiogetpacketsrc(pipe->fd, &msgh) < 0) {
if (xiogetpacketsrc(pipe->fd, &msgh,
MSG_PEEK
#ifdef MSG_TRUNC
|MSG_TRUNC
#endif
) < 0) {
return -1;
}
xiodopacketinfo(&msgh, true, false);