diff --git a/CHANGES b/CHANGES index 8cdb69baa5..386bffb220 100644 --- a/CHANGES +++ b/CHANGES @@ -40,6 +40,7 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group another incorporate-remote-capture project. (issue #1120) rpcapd: Refine SSL options in printusage(). Fix a possible buffer overflow (Coverity CID 1619148). + Add API to customize the keepalives parameters of a rpcap control socket Documentation: Document a standard format for writing out BPF filter programs. Add a README.hurd.md file. diff --git a/CMakeLists.txt b/CMakeLists.txt index 17ece6ef70..e3097627c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3391,6 +3391,7 @@ set(MAN3PCAP_NOEXPAND pcap_offline_filter.3pcap pcap_open_live.3pcap pcap_set_buffer_size.3pcap + pcap_set_control_keepalive.3pcap pcap_set_datalink.3pcap pcap_set_promisc.3pcap pcap_set_protocol_linux.3pcap diff --git a/Makefile.in b/Makefile.in index a8314c32fa..11ea634895 100644 --- a/Makefile.in +++ b/Makefile.in @@ -202,6 +202,7 @@ MAN3PCAP_NOEXPAND = \ pcap_offline_filter.3pcap \ pcap_open_live.3pcap \ pcap_set_buffer_size.3pcap \ + pcap_set_control_keepalive.3pcap \ pcap_set_datalink.3pcap \ pcap_set_promisc.3pcap \ pcap_set_protocol_linux.3pcap \ diff --git a/pcap-int.h b/pcap-int.h index 3b85492915..7a88004e81 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -197,6 +197,7 @@ typedef int (*getnonblock_op_t)(pcap_t *); typedef int (*setnonblock_op_t)(pcap_t *, int); typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); typedef void (*breakloop_op_t)(pcap_t *); +typedef int (*set_control_keepalive_op_t)(pcap_t *, int, int, int, int); #ifdef _WIN32 typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *); typedef int (*setbuff_op_t)(pcap_t *, int); @@ -339,6 +340,7 @@ struct pcap { setnonblock_op_t setnonblock_op; stats_op_t stats_op; breakloop_op_t breakloop_op; + set_control_keepalive_op_t set_control_keepalive_op; /* * Routine to use as callback for pcap_next()/pcap_next_ex(). diff --git a/pcap-rpcap.c b/pcap-rpcap.c index fd3cf6abb9..5877f2bc23 100644 --- a/pcap-rpcap.c +++ b/pcap-rpcap.c @@ -41,6 +41,11 @@ #include /* for functions with variable number of arguments */ #include /* for the errno variable */ #include /* for INT_MAX */ + +#ifndef _WIN32 + #include /* for TCP_KEEP* */ +#endif + #include "sockutils.h" #include "pcap-int.h" #include "pcap-util.h" @@ -178,6 +183,7 @@ static int rpcap_recv(PCAP_SOCKET sock, SSL *, void *buffer, size_t toread, uint static void rpcap_msg_err(PCAP_SOCKET sockctrl, SSL *, uint32_t plen, char *remote_errbuf); static int rpcap_discard(PCAP_SOCKET sock, SSL *, uint32_t len, char *errbuf); static int rpcap_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size); +static int pcap_set_control_keepalive_rpcap(pcap_t *p, int enable, int keepcnt, int keepidle, int keepintvl); /**************************************************** * * @@ -2646,6 +2652,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim #ifdef _WIN32 fp->stats_ex_op = pcap_stats_ex_rpcap; #endif + fp->set_control_keepalive_op = pcap_set_control_keepalive_rpcap; fp->cleanup_op = pcap_cleanup_rpcap; fp->activated = 1; @@ -3718,3 +3725,46 @@ static int rpcap_read_packet_msg(struct pcap_rpcap const *rp, pcap_t *p, size_t p->cc = cc; return 0; } + +/* + * Set the keepalives parameters on the control socket. + * An rpcap-based application may detect more rapidly a network error. + * + * It may not be necessary to set them on the data socket as it may use UDP. + * See pcap_read_nocb_remote for the select logic that will take into + * account the error on the control socket. + */ +static int +pcap_set_control_keepalive_rpcap(pcap_t *p, int enable, int keepcnt, int keepidle, int keepintvl) +{ + struct pcap_rpcap *pr = p->priv; /* structure used when doing a remote live capture */ + + if (setsockopt(pr->rmt_sockctrl, SOL_SOCKET, SO_KEEPALIVE, (char *)&enable, sizeof(enable)) < 0) + { + sock_geterrmsg(p->errbuf, PCAP_ERRBUF_SIZE, "setsockopt(): "); + return PCAP_ERROR; + } + + /* when SO_KEEPALIVE isn't active, the following options aren't used */ + if (!enable) + return 0; + +#if defined(TCP_KEEPCNT) && defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) + if (setsockopt(pr->rmt_sockctrl, IPPROTO_TCP, TCP_KEEPCNT, (char *)&keepcnt, sizeof(keepcnt)) < 0 || + setsockopt(pr->rmt_sockctrl, IPPROTO_TCP, TCP_KEEPIDLE, (char *)&keepidle, sizeof(keepidle)) < 0 || + setsockopt(pr->rmt_sockctrl, IPPROTO_TCP, TCP_KEEPINTVL, (char *)&keepintvl, sizeof(keepintvl)) < 0) + { + sock_geterrmsg(p->errbuf, PCAP_ERRBUF_SIZE, "setsockopt(): "); + return PCAP_ERROR; + } +#else + if (keepcnt || keepidle || keepintvl) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "TCP_KEEPCNT, TCP_KEEPIDLE or TCP_KEEPINTVL not supported on this platform"); + return PCAP_ERROR; + } +#endif + + return 0; +} diff --git a/pcap.c b/pcap.c index 2ff17e1629..67b7792631 100644 --- a/pcap.c +++ b/pcap.c @@ -379,6 +379,20 @@ pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_) return (PCAP_ERROR_NOT_ACTIVATED); } +static int +pcap_set_control_keepalive_not_initialized(pcap_t *pcap, int enable _U_, + int keepcnt _U_, int keepidle _U_, int keepintvl _U_) +{ + if (pcap->activated) { + /* Not set by the module, so probably not supported */ + return PCAP_WARNING_CONTROL_KEEPALIVE_NOTSUP; + } + /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */ + (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); + return (PCAP_ERROR_NOT_ACTIVATED); +} + #ifdef _WIN32 static struct pcap_stat * pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_) @@ -2412,6 +2426,7 @@ initialize_ops(pcap_t *p) p->set_datalink_op = pcap_set_datalink_not_initialized; p->getnonblock_op = pcap_getnonblock_not_initialized; p->stats_op = pcap_stats_not_initialized; + p->set_control_keepalive_op = pcap_set_control_keepalive_not_initialized; #ifdef _WIN32 p->stats_ex_op = pcap_stats_ex_not_initialized; p->setbuff_op = pcap_setbuff_not_initialized; @@ -3706,6 +3721,10 @@ pcap_statustostr(int errnum) case PCAP_ERROR_CAPTURE_NOTSUP: return ("Packet capture is not supported on that device"); + + case PCAP_WARNING_CONTROL_KEEPALIVE_NOTSUP: + return ("Keepalive control is not supported"); + } (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); return(ebuf); @@ -3852,6 +3871,12 @@ pcap_stats(pcap_t *p, struct pcap_stat *ps) return (p->stats_op(p, ps)); } +int +pcap_set_control_keepalive(pcap_t *p, int enable, int keepcnt, int keepidle, int keepintvl) +{ + return p->set_control_keepalive_op(p, enable, keepcnt, keepidle, keepintvl); +} + #ifdef _WIN32 struct pcap_stat * pcap_stats_ex(pcap_t *p, int *pcap_stat_size) diff --git a/pcap/pcap.h b/pcap/pcap.h index 9560df524f..628cef15f8 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -370,6 +370,7 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, #define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */ #define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */ #define PCAP_ERROR_CAPTURE_NOTSUP -13 /* capture mechanism not available */ +#define PCAP_WARNING_CONTROL_KEEPALIVE_NOTSUP -14 /* keepalive control is not supported */ /* * Warning codes for the pcap API. @@ -612,6 +613,9 @@ PCAP_AVAILABLE_0_4 PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *) PCAP_WARN_UNUSED_RESULT; +PCAP_AVAILABLE_1_11 +PCAP_API int pcap_set_control_keepalive(pcap_t *, int, int, int, int); + PCAP_AVAILABLE_0_4 PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *) PCAP_WARN_UNUSED_RESULT; diff --git a/pcap_set_control_keepalive.3pcap b/pcap_set_control_keepalive.3pcap new file mode 100644 index 0000000000..fa9d9f938c --- /dev/null +++ b/pcap_set_control_keepalive.3pcap @@ -0,0 +1,56 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_CONTROL_KEEPALIVE 3PCAP "20 September 2022" +.SH NAME +pcap_set_control_keepalive \- set the keepalives parameters on a rpcap control socket. +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_control_keepalive(pcap_t *p, int enable, int keepcnt, int keepidle, int keepintvl) +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_control_keepalive () +set the keepalives parameters on the control socket. +The arguments +.I keepcnt +, +.I keepidle +, and +.I keepintvl +are used to set the corresponding tcp options. Respectively +.B TCP_KEEPCNT +(The maximum number of keepalive probes TCP should send before dropping the connection), +.B TCP_KEEPIDLE +(The time in seconds the connection needs to remain idle before TCP starts sending keepalive probes), and +.B TCP_KEEPINTVL +(The time in seconds between individual keepalive probes). +.SH RETURN VALUE +.BR pcap_set_control_keepalive () +returns +.B 0 +on success or +.B PCAP_ERROR +if we failed to set the socket options. +.SH SEE ALSO +.BR pcap (3PCAP),