mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
Corrected handling of IP_RECVERR
This commit is contained in:
parent
bc32acb5fe
commit
d84c22be7a
6 changed files with 177 additions and 28 deletions
4
CHANGES
4
CHANGES
|
@ -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
35
filan.c
|
@ -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) {
|
||||
|
|
87
xio-ip.c
87
xio-ip.c
|
@ -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;
|
||||
|
|
63
xio-socket.c
63
xio-socket.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
14
xioread.c
14
xioread.c
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue