PPP_FILTER opt_ppp.h
SLIP_IFF_OPTS opt_slip.h
TCPDEBUG
+TCP_SIGNATURE opt_inet.h
TCP_DROP_SYNFIN opt_tcp_input.h
XBONEHACK
options ACCEPT_FILTER_DATA
options ACCEPT_FILTER_HTTP
+# TCP_SIGNATURE adds support for RFC 2385 (TCP-MD5) digests. These are
+# carried in TCP option 19. This option is commonly used to protect
+# TCP sessions (e.g. BGP) where IPSEC is not available nor desirable.
+# This is enabled on a per-socket basis using the TCP_MD5SIG socket option.
+# This requires the use of 'device crypto', 'options IPSEC'
+# or 'device cryptodev'.
+options TCP_SIGNATURE #include support for RFC 2385
+
#
# TCP_DROP_SYNFIN adds support for ignoring TCP packets with SYN+FIN. This
# prevents nmap et al. from identifying the TCP/IP stack, but breaks support
#define IP_MSS 576 /* default maximum segment size */
+/*
+ * This is the real IPv4 pseudo header, used for computing the TCP and UDP
+ * checksums. For the Internet checksum, struct ipovly can be used instead.
+ * For stronger checksums, the real thing must be used.
+ */
+struct ippseudo {
+ struct in_addr ippseudo_src; /* source internet address */
+ struct in_addr ippseudo_dst; /* destination internet address */
+ u_int8_t ippseudo_pad; /* pad, must be zero */
+ u_int8_t ippseudo_p; /* protocol */
+ u_int16_t ippseudo_len; /* protocol length */
+} __packed;
#endif
case IPSEC_POLICY_BYPASS:
case IPSEC_POLICY_NONE:
+ case IPSEC_POLICY_TCP:
/* no need to do IPsec. */
goto skip_ipsec;
#define TCPOPT_CC 11 /* CC options: RFC-1644 */
#define TCPOPT_CCNEW 12
#define TCPOPT_CCECHO 13
+#define TCPOPT_SIGNATURE 19 /* Keyed MD5: RFC 2385 */
+#define TCPOLEN_SIGNATURE 18
/*
* Default maximum segment size for TCP.
#define TCP_MAXSEG 0x02 /* set maximum segment size */
#define TCP_NOPUSH 0x04 /* don't push last block of write */
#define TCP_NOOPT 0x08 /* don't use TCP options */
+#define TCP_SIGNATURE_ENABLE 0x10 /* use MD5 digests (RFC2385) */
#endif
*/
#include "opt_ipfw.h" /* for ipfw_fwd */
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_tcpdebug.h"
struct inpcb *inp = NULL;
u_char *optp = NULL;
int optlen = 0;
- int len, tlen, off;
+ int tlen, off;
+ int len = 0;
int drop_hdrlen;
struct tcpcb *tp = NULL;
int thflags;
r->rblk_end = ntohl(r->rblk_end);
}
break;
+#ifdef TCP_SIGNATURE
+ /*
+ * XXX In order to reply to a host which has set the
+ * TCP_SIGNATURE option in its initial SYN, we have to
+ * record the fact that the option was observed here
+ * for the syncache code to perform the correct response.
+ */
+ case TCPOPT_SIGNATURE:
+ if (optlen != TCPOLEN_SIGNATURE)
+ continue;
+ to->to_flags |= (TOF_SIGNATURE | TOF_SIGLEN);
+ break;
+#endif /* TCP_SIGNATURE */
default:
continue;
}
* $DragonFly: src/sys/netinet/tcp_output.c,v 1.34 2007/04/22 01:13:14 dillon Exp $
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_tcpdebug.h"
long len, recvwin, sendwin;
int nsacked = 0;
int off, flags, error;
+#ifdef TCP_SIGNATURE
+ int sigoff = 0;
+#endif
struct mbuf *m;
struct ip *ip = NULL;
struct ipovly *ipov = NULL;
tp->reportblk.rblk_start != tp->reportblk.rblk_end))
tcp_sack_fill_report(tp, opt, &optlen);
+#ifdef TCP_SIGNATURE
+ if (tp->t_flags & TF_SIGNATURE) {
+ int i;
+ u_char *bp;
+ /*
+ * Initialize TCP-MD5 option (RFC2385)
+ */
+ bp = (u_char *)opt + optlen;
+ *bp++ = TCPOPT_SIGNATURE;
+ *bp++ = TCPOLEN_SIGNATURE;
+ sigoff = optlen + 2;
+ for (i = 0; i < TCP_SIGLEN; i++)
+ *bp++ = 0;
+ optlen += TCPOLEN_SIGNATURE;
+ /*
+ * Terminate options list and maintain 32-bit alignment.
+ */
+ *bp++ = TCPOPT_NOP;
+ *bp++ = TCPOPT_EOL;
+ optlen += 2;
+ }
+#endif /* TCP_SIGNATURE */
KASSERT(optlen <= TCP_MAXOLEN, ("too many TCP options"));
hdrlen += optlen;
tp->snd_up = tp->snd_una; /* drag it along */
}
+#ifdef TCP_SIGNATURE
+ if (tp->t_flags & TF_SIGNATURE)
+ tcpsignature_compute(m, len, optlen,
+ (u_char *)(th + 1) + sigoff, IPSEC_DIR_OUTBOUND);
+#endif /* TCP_SIGNATURE */
+
/*
* Put TCP length in extended header, and then
* checksum extended header and data.
*/
#include "opt_compat.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_tcpdebug.h"
#ifdef IPSEC
#include <netinet6/ipsec.h>
+#include <netproto/key/key.h>
#ifdef INET6
#include <netinet6/ipsec6.h>
#endif
bwnd = tp->t_maxseg * 2;
tp->snd_bwnd = bwnd;
}
+
+#ifdef TCP_SIGNATURE
+/*
+ * Compute TCP-MD5 hash of a TCP segment. (RFC2385)
+ *
+ * We do this over ip, tcphdr, segment data, and the key in the SADB.
+ * When called from tcp_input(), we can be sure that th_sum has been
+ * zeroed out and verified already.
+ *
+ * Return 0 if successful, otherwise return -1.
+ *
+ * XXX The key is retrieved from the system's PF_KEY SADB, by keying a
+ * search with the destination IP address, and a 'magic SPI' to be
+ * determined by the application. This is hardcoded elsewhere to 1179
+ * right now. Another branch of this code exists which uses the SPD to
+ * specify per-application flows but it is unstable.
+ */
+int
+tcpsignature_compute(
+ struct mbuf *m, /* mbuf chain */
+ int len, /* length of TCP data */
+ int optlen, /* length of TCP options */
+ u_char *buf, /* storage for MD5 digest */
+ u_int direction) /* direction of flow */
+{
+ struct ippseudo ippseudo;
+ MD5_CTX ctx;
+ int doff;
+ struct ip *ip;
+ struct ipovly *ipovly;
+ struct secasvar *sav;
+ struct tcphdr *th;
+#ifdef INET6
+ struct ip6_hdr *ip6;
+ struct in6_addr in6;
+ uint32_t plen;
+ uint16_t nhdr;
+#endif /* INET6 */
+ u_short savecsum;
+
+ KASSERT(m != NULL, ("passed NULL mbuf. Game over."));
+ KASSERT(buf != NULL, ("passed NULL storage pointer for MD5 signature"));
+ /*
+ * Extract the destination from the IP header in the mbuf.
+ */
+ ip = mtod(m, struct ip *);
+#ifdef INET6
+ ip6 = NULL; /* Make the compiler happy. */
+#endif /* INET6 */
+ /*
+ * Look up an SADB entry which matches the address found in
+ * the segment.
+ */
+ switch (IP_VHL_V(ip->ip_vhl)) {
+ case IPVERSION:
+ sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
+ IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ break;
+#ifdef INET6
+ case (IPV6_VERSION >> 4):
+ ip6 = mtod(m, struct ip6_hdr *);
+ sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
+ IPPROTO_TCP, htonl(TCP_SIG_SPI));
+ break;
+#endif /* INET6 */
+ default:
+ return (EINVAL);
+ /* NOTREACHED */
+ break;
+ }
+ if (sav == NULL) {
+ kprintf("%s: SADB lookup failed\n", __func__);
+ return (EINVAL);
+ }
+ MD5Init(&ctx);
+
+ /*
+ * Step 1: Update MD5 hash with IP pseudo-header.
+ *
+ * XXX The ippseudo header MUST be digested in network byte order,
+ * or else we'll fail the regression test. Assume all fields we've
+ * been doing arithmetic on have been in host byte order.
+ * XXX One cannot depend on ipovly->ih_len here. When called from
+ * tcp_output(), the underlying ip_len member has not yet been set.
+ */
+ switch (IP_VHL_V(ip->ip_vhl)) {
+ case IPVERSION:
+ ipovly = (struct ipovly *)ip;
+ ippseudo.ippseudo_src = ipovly->ih_src;
+ ippseudo.ippseudo_dst = ipovly->ih_dst;
+ ippseudo.ippseudo_pad = 0;
+ ippseudo.ippseudo_p = IPPROTO_TCP;
+ ippseudo.ippseudo_len = htons(len + sizeof(struct tcphdr) + optlen);
+ MD5Update(&ctx, (char *)&ippseudo, sizeof(struct ippseudo));
+ th = (struct tcphdr *)((u_char *)ip + sizeof(struct ip));
+ doff = sizeof(struct ip) + sizeof(struct tcphdr) + optlen;
+ break;
+#ifdef INET6
+ /*
+ * RFC 2385, 2.0 Proposal
+ * For IPv6, the pseudo-header is as described in RFC 2460, namely the
+ * 128-bit source IPv6 address, 128-bit destination IPv6 address, zero-
+ * extended next header value (to form 32 bits), and 32-bit segment
+ * length.
+ * Note: Upper-Layer Packet Length comes before Next Header.
+ */
+ case (IPV6_VERSION >> 4):
+ in6 = ip6->ip6_src;
+ in6_clearscope(&in6);
+ MD5Update(&ctx, (char *)&in6, sizeof(struct in6_addr));
+ in6 = ip6->ip6_dst;
+ in6_clearscope(&in6);
+ MD5Update(&ctx, (char *)&in6, sizeof(struct in6_addr));
+ plen = htonl(len + sizeof(struct tcphdr) + optlen);
+ MD5Update(&ctx, (char *)&plen, sizeof(uint32_t));
+ nhdr = 0;
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ nhdr = IPPROTO_TCP;
+ MD5Update(&ctx, (char *)&nhdr, sizeof(uint8_t));
+ th = (struct tcphdr *)((u_char *)ip6 + sizeof(struct ip6_hdr));
+ doff = sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + optlen;
+ break;
+#endif /* INET6 */
+ default:
+ return (EINVAL);
+ /* NOTREACHED */
+ break;
+ }
+ /*
+ * Step 2: Update MD5 hash with TCP header, excluding options.
+ * The TCP checksum must be set to zero.
+ */
+ savecsum = th->th_sum;
+ th->th_sum = 0;
+ MD5Update(&ctx, (char *)th, sizeof(struct tcphdr));
+ th->th_sum = savecsum;
+ /*
+ * Step 3: Update MD5 hash with TCP segment data.
+ * Use m_apply() to avoid an early m_pullup().
+ */
+ if (len > 0)
+ m_apply(m, doff, len, tcpsignature_apply, &ctx);
+ /*
+ * Step 4: Update MD5 hash with shared secret.
+ */
+ MD5Update(&ctx, _KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
+ MD5Final(buf, &ctx);
+ key_sa_recordxfer(sav, m);
+ key_freesav(sav);
+ return (0);
+}
+
+int
+tcpsignature_apply(void *fstate, void *data, unsigned int len)
+{
+
+ MD5Update((MD5_CTX *)fstate, (unsigned char *)data, len);
+ return (0);
+}
+#endif /* TCP_SIGNATURE */
* $DragonFly: src/sys/netinet/tcp_syncache.c,v 1.35 2008/11/22 11:03:35 sephe Exp $
*/
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
if (sc->sc_flags & SCF_SACK_PERMITTED)
tp->t_flags |= TF_SACK_PERMITTED;
+#ifdef TCP_SIGNATURE
+ if (sc->sc_flags & SCF_SIGNATURE)
+ tp->t_flags |= TF_SIGNATURE;
+#endif /* TCP_SIGNATURE */
+
+
tcp_mss(tp, sc->sc_peer_mss);
/*
sc->sc_flags |= SCF_SACK_PERMITTED;
if (tp->t_flags & TF_NOOPT)
sc->sc_flags = SCF_NOOPT;
+#ifdef TCP_SIGNATURE
+ /*
+ * If listening socket requested TCP digests, and received SYN
+ * contains the option, flag this in the syncache so that
+ * syncache_respond() will do the right thing with the SYN+ACK.
+ * XXX Currently we always record the option by default and will
+ * attempt to use it in syncache_respond().
+ */
+ if (to->to_flags & TOF_SIGNATURE)
+ sc->sc_flags = SCF_SIGNATURE;
+#endif /* TCP_SIGNATURE */
if (syncache_respond(sc, m) == 0) {
syncache_insert(sc, sch);
((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0) +
((sc->sc_flags & SCF_SACK_PERMITTED) ?
TCPOLEN_SACK_PERMITTED_ALIGNED : 0);
+#ifdef TCP_SIGNATURE
+ optlen += ((sc->sc_flags & SCF_SIGNATURE) ?
+ (TCPOLEN_SIGNATURE + 2) : 0);
+#endif /* TCP_SIGNATURE */
}
tlen = hlen + sizeof(struct tcphdr) + optlen;
optp += TCPOLEN_TSTAMP_APPA;
}
+#ifdef TCP_SIGNATURE
+ /*
+ * Handle TCP-MD5 passive opener response.
+ */
+ if (sc->sc_flags & SCF_SIGNATURE) {
+ u_int8_t *bp = optp;
+ int i;
+
+ *bp++ = TCPOPT_SIGNATURE;
+ *bp++ = TCPOLEN_SIGNATURE;
+ for (i = 0; i < TCP_SIGLEN; i++)
+ *bp++ = 0;
+ tcpsignature_compute(m, 0, optlen,
+ optp + 2, IPSEC_DIR_OUTBOUND);
+ *bp++ = TCPOPT_NOP;
+ *bp++ = TCPOPT_EOL;
+ optp += TCPOLEN_SIGNATURE + 2;
+}
+#endif /* TCP_SIGNATURE */
+
if (sc->sc_flags & SCF_SACK_PERMITTED) {
*((u_int32_t *)optp) = htonl(TCPOPT_SACK_PERMITTED_ALIGNED);
optp += TCPOLEN_SACK_PERMITTED_ALIGNED;
*/
#include "opt_ipsec.h"
+#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_tcpdebug.h"
if (error)
break;
switch (sopt->sopt_name) {
+#ifdef TCP_SIGNATURE
+ case TCP_SIGNATURE_ENABLE:
+ if (optval > 0)
+ tp->t_flags |= TF_SIGNATURE;
+ else
+ tp->t_flags &= ~TF_SIGNATURE;
+ break;
+#endif /* TCP_SIGNATURE */
case TCP_NODELAY:
case TCP_NOOPT:
switch (sopt->sopt_name) {
case SOPT_GET:
switch (sopt->sopt_name) {
+#ifdef TCP_SIGNATURE
+ case TCP_SIGNATURE_ENABLE:
+ optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0;
+ break;
+#endif /* TCP_SIGNATURE */
case TCP_NODELAY:
optval = tp->t_flags & TF_NODELAY;
break;
#define TF_NEEDFIN 0x00000800 /* send FIN (implicit state) */
#define TF_NOPUSH 0x00001000 /* don't push */
#define TF_SYNCACHE 0x00002000 /* syncache present */
-/* 0x00001000 - 0x00008000 were used for T/TCP */
+#define TF_SIGNATURE 0x00004000 /* require MD5 digests (RFC2385) */
#define TF_MORETOCOME 0x00010000 /* More data to be appended to sock */
#define TF_LQ_OVERFLOW 0x00020000 /* listen queue overflow */
#define TF_LASTIDLE 0x00040000 /* connection was previously idle */
#define ENTER_FASTRECOVERY(tp) tp->t_flags |= TF_FASTRECOVERY
#define EXIT_FASTRECOVERY(tp) tp->t_flags &= ~TF_FASTRECOVERY
+#ifdef TCP_SIGNATURE
+/*
+ * Defines which are needed by the xform_tcp module and tcp_[in|out]put
+ * for SADB verification and lookup.
+ */
+#define TCP_SIGLEN 16 /* length of computed digest in bytes */
+#define TCP_KEYLEN_MIN 1 /* minimum length of TCP-MD5 key */
+#define TCP_KEYLEN_MAX 80 /* maximum length of TCP-MD5 key */
+/*
+ * Only a single SA per host may be specified at this time. An SPI is
+ * needed in order for the KEY_ALLOCSA() lookup to work.
+ */
+#define TCP_SIG_SPI 0x1000
+#endif /* TCP_SIGNATURE */
+
/*
* TCP statistics.
*/
#define TOF_SCALE 0x0020
#define TOF_SACK_PERMITTED 0x0040
#define TOF_SACK 0x0080
+#define TOF_SIGNATURE 0x0100 /* signature option present */
+#define TOF_SIGLEN 0x0200 /* sigature length valid (RFC2385) */
u_int32_t to_tsval;
u_int32_t to_tsecr;
u_int16_t to_mss;
#define SCF_TIMESTAMP 0x04 /* negotiated timestamps */
#define SCF_UNREACH 0x10 /* icmp unreachable received */
#define SCF_SACK_PERMITTED 0x20 /* saw SACK permitted option */
+#define SCF_SIGNATURE 0x40 /* send MD5 digests */
#define SCF_MARKER 0x80 /* not a real entry */
TAILQ_ENTRY(syncache) sc_hash;
TAILQ_ENTRY(syncache) sc_timerq;
void syncache_badack(struct in_conninfo *);
void syncache_destroy(struct tcpcb *tp);
+#ifdef TCP_SIGNATURE
+int tcpsignature_apply(void *fstate, void *data, unsigned int len);
+int tcpsignature_compute(struct mbuf *m, int len, int tcpoptlen,
+ u_char *buf, u_int direction);
+#endif /* TCP_SIGNATURE */
extern struct pr_usrreqs tcp_usrreqs;
extern u_long tcp_sendspace;
#define IPSEC_MODE_ANY 0 /* i.e. wildcard. */
#define IPSEC_MODE_TRANSPORT 1
#define IPSEC_MODE_TUNNEL 2
+#define IPSEC_MODE_TCPMD5 3 /* TCP MD5 mode */
/*
* Direction of security policy.
#define IPSEC_POLICY_IPSEC 2 /* do IPsec */
#define IPSEC_POLICY_ENTRUST 3 /* consulting SPD if present. */
#define IPSEC_POLICY_BYPASS 4 /* only for privileged socket. */
+#define IPSEC_POLICY_TCP 5 /* TCP MD5 policy */
/* Security protocol level */
#define IPSEC_LEVEL_DEFAULT 0 /* reference to system default */
switch (mhp->msg->sadb_msg_satype) {
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) &&
sav->alg_auth != SADB_X_AALG_NULL)
error = EINVAL;
sav->key_enc = NULL; /*just in case*/
break;
case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_TCPSIGNATURE:
default:
error = EINVAL;
break;
break;
case SADB_SATYPE_AH:
case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
break;
default:
ipseclog((LOG_DEBUG, "key_setsaval: invalid SA type.\n"));
checkmask = 4;
mustmask = 4;
break;
+ case IPPROTO_TCP:
+ if (sav->alg_auth != SADB_X_AALG_TCP_MD5) {
+ ipseclog((LOG_DEBUG, "key_mature: "
+ "protocol and algorithm mismated.\n"));
+ return(EINVAL);
+ }
+ checkmask = 0;
+ mustmask = 0;
+ break;
default:
ipseclog((LOG_DEBUG, "key_mature: Invalid satype.\n"));
return EPROTONOSUPPORT;
return IPPROTO_ESP;
case SADB_X_SATYPE_IPCOMP:
return IPPROTO_IPCOMP;
+ case SADB_X_SATYPE_TCPSIGNATURE:
+ return IPPROTO_TCP;
break;
default:
return 0;
return SADB_SATYPE_ESP;
case IPPROTO_IPCOMP:
return SADB_X_SATYPE_IPCOMP;
+ case IPPROTO_TCP:
+ return SADB_X_SATYPE_TCPSIGNATURE;
break;
default:
return 0;
case SADB_SATYPE_AH:
case SADB_SATYPE_ESP:
case SADB_X_SATYPE_IPCOMP:
+ case SADB_X_SATYPE_TCPSIGNATURE:
switch (msg->sadb_msg_type) {
case SADB_X_SPDADD:
case SADB_X_SPDDELETE: