summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if_pppx.c10
-rw-r--r--sys/net/pipex.c206
-rw-r--r--sys/net/pipex.h7
-rw-r--r--sys/net/pipex_local.h15
4 files changed, 172 insertions, 66 deletions
diff --git a/sys/net/if_pppx.c b/sys/net/if_pppx.c
index 09e1133feae..f4f12ce9333 100644
--- a/sys/net/if_pppx.c
+++ b/sys/net/if_pppx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pppx.c,v 1.11 2011/08/21 09:00:15 jmatthew Exp $ */
+/* $OpenBSD: if_pppx.c,v 1.12 2011/10/15 03:24:11 yasuoka Exp $ */
/*
* Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
@@ -805,9 +805,13 @@ pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
#endif
#ifdef PIPEX_MPPE
if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
- pipex_mppe_req_init(&req->pr_mppe_recv, &session->mppe_recv);
+ pipex_session_init_mppe_recv(session,
+ req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
+ req->pr_mppe_recv.master_key);
if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
- pipex_mppe_req_init(&req->pr_mppe_send, &session->mppe_send);
+ pipex_session_init_mppe_send(session,
+ req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
+ req->pr_mppe_send.master_key);
if (pipex_session_is_mppe_required(session)) {
if (!pipex_session_is_mppe_enabled(session) ||
diff --git a/sys/net/pipex.c b/sys/net/pipex.c
index 93955f394d7..87be24931e3 100644
--- a/sys/net/pipex.c
+++ b/sys/net/pipex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pipex.c,v 1.21 2011/07/09 04:11:15 dhill Exp $ */
+/* $OpenBSD: pipex.c,v 1.22 2011/10/15 03:24:11 yasuoka Exp $ */
/*-
* Copyright (c) 2009 Internet Initiative Japan Inc.
@@ -119,9 +119,6 @@ int pipex_debug = 0; /* systcl net.inet.ip.pipex_debug */
/* PPP compression == MPPE is assumed, so don't answer CCP Reset-Request. */
#define PIPEX_NO_CCP_RESETACK 1
-/* see the comment on pipex_mppe_input() */
-#define WORKAROUND_OUT_OF_SEQUENCE_PPP_FRAMING 1
-
/************************************************************************
* Core functions
************************************************************************/
@@ -394,9 +391,13 @@ pipex_add_session(struct pipex_session_req *req,
#endif
#ifdef PIPEX_MPPE
if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
- pipex_mppe_req_init(&req->pr_mppe_recv, &session->mppe_recv);
+ pipex_session_init_mppe_recv(session,
+ req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
+ req->pr_mppe_recv.master_key);
if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
- pipex_mppe_req_init(&req->pr_mppe_send, &session->mppe_send);
+ pipex_session_init_mppe_send(session,
+ req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
+ req->pr_mppe_send.master_key);
if (pipex_session_is_mppe_required(session)) {
if (!pipex_session_is_mppe_enabled(session) ||
@@ -609,6 +610,9 @@ pipex_destroy_session(struct pipex_session *session)
pipex_timer_stop();
splx(s);
+
+ if (session->mppe_recv.old_session_keys)
+ free(session->mppe_recv.old_session_keys, M_TEMP);
free(session, M_TEMP);
return (0);
@@ -1614,6 +1618,7 @@ pipex_pptp_input(struct mbuf *m0, struct pipex_session *session)
struct ip *ip;
struct pipex_gre_header *gre;
struct pipex_pptp_session *pptp_session;
+ int rewind = 0;
KASSERT(m0->m_pkthdr.len >= PIPEX_IPGRE_HDRLEN);
pptp_session = &session->proto.pptp;
@@ -1650,11 +1655,11 @@ pipex_pptp_input(struct mbuf *m0, struct pipex_session *session)
if (ack + 1 == pptp_session->snd_una) {
/* ack has not changed before */
} else if (SEQ32_LT(ack, pptp_session->snd_una)) {
- reason = "ack out of sequence";
- goto inseq;
+ /* OoO ack packets should not be dropped. */
+ rewind = 1;
} else if (SEQ32_GT(ack, pptp_session->snd_nxt)) {
reason = "ack for unknown sequence";
- goto inseq;
+ goto out_seq;
} else {
ack++;
pptp_session->snd_una = ack;
@@ -1665,8 +1670,12 @@ pipex_pptp_input(struct mbuf *m0, struct pipex_session *session)
goto not_ours;
}
if (SEQ32_LT(seq, pptp_session->rcv_nxt)) {
- reason = "out of sequence";
- goto inseq;
+ rewind = 1;
+ if (SEQ32_LT(seq,
+ pptp_session->rcv_nxt - PIPEX_REWIND_LIMIT)) {
+ reason = "out of sequence";
+ goto out_seq;
+ }
} else if (SEQ32_GE(seq, pptp_session->rcv_nxt +
pptp_session->maxwinsz)) {
pipex_session_log(session, LOG_DEBUG,
@@ -1678,18 +1687,24 @@ pipex_pptp_input(struct mbuf *m0, struct pipex_session *session)
seq++;
nseq = SEQ32_SUB(seq, pptp_session->rcv_nxt);
- pptp_session->rcv_nxt = seq;
-
- if (SEQ32_SUB(seq, pptp_session->rcv_acked) >
- roundup(pptp_session->winsz, 2) / 2) /* Send ack only packet. */
- pipex_pptp_output(NULL, session, 0, 1);
+ if (!rewind) {
+ pptp_session->rcv_nxt = seq;
+ if (SEQ32_SUB(seq, pptp_session->rcv_acked) >
+ roundup(pptp_session->winsz, 2) / 2) /* Send ack only packet. */
+ pipex_pptp_output(NULL, session, 0, 1);
+ }
if ((m0 = pipex_common_input(session, m0, hlen, (int)ntohs(gre->len)))
== NULL) {
/* ok, The packet is for PIPEX */
- session->proto.pptp.rcv_gap += nseq;
- return (m0);
+ if (!rewind)
+ session->proto.pptp.rcv_gap += nseq;
+ return (NULL);
}
+
+ if (rewind)
+ goto out_seq;
+
not_ours:
/* revert original seq/ack values */
seq--;
@@ -1720,7 +1735,7 @@ not_ours:
}
return (m0);
-inseq:
+out_seq:
pipex_session_log(session, LOG_DEBUG,
"Received bad data packet: %s: seq=%u(%u-%u) ack=%u(%u-%u)",
reason, seq, pptp_session->rcv_nxt,
@@ -2054,6 +2069,7 @@ pipex_l2tp_input(struct mbuf *m0, int off0, struct pipex_session *session)
int length, offset, hlen, nseq;
u_char *cp, *nsp, *nrp;
uint16_t flags, ns = 0, nr = 0;
+ int rewind = 0;
length = offset = ns = nr = 0;
l2tp_session = &session->proto.l2tp;
@@ -2098,13 +2114,17 @@ pipex_l2tp_input(struct mbuf *m0, int off0, struct pipex_session *session)
SEQ16_LE(nr, l2tp_session->ns_nxt))
/* update 'ns_una' only if the ns is in valid range */
l2tp_session->ns_una = nr;
-
- if (SEQ16_LT(ns, l2tp_session->nr_nxt))
- goto out_seq;
+ if (SEQ16_LT(ns, l2tp_session->nr_nxt)) {
+ rewind = 1;
+ if (SEQ16_LT(ns,
+ l2tp_session->nr_nxt - PIPEX_REWIND_LIMIT))
+ goto out_seq;
+ }
ns++;
nseq = SEQ16_SUB(ns, l2tp_session->nr_nxt);
- l2tp_session->nr_nxt = ns;
+ if (!rewind)
+ l2tp_session->nr_nxt = ns;
}
if (flags & PIPEX_L2TP_FLAG_OFFSET)
GETSHORT(offset, cp);
@@ -2113,10 +2133,14 @@ pipex_l2tp_input(struct mbuf *m0, int off0, struct pipex_session *session)
hlen += off0 + offset;
if ((m0 = pipex_common_input(session, m0, hlen, length)) == NULL) {
/* ok, The packet is for PIPEX */
- session->proto.l2tp.nr_gap += nseq;
+ if (!rewind)
+ session->proto.l2tp.nr_gap += nseq;
return (NULL);
}
+ if (rewind)
+ goto out_seq;
+
/*
* overwrite sequence numbers to adjust a gap between pipex and
* userland.
@@ -2279,17 +2303,23 @@ pipex_l2tp_userland_output(struct mbuf *m0, struct pipex_session *session)
* MPPE
***********************************************************************/
#define PIPEX_COHERENCY_CNT_MASK 0x0fff
-
Static void
-pipex_mppe_req_init(struct pipex_mppe_req *mppe_req, struct pipex_mppe *mppe)
+pipex_mppe_init(struct pipex_mppe *mppe, int stateless, int keylenbits,
+ u_char *master_key, int has_oldkey)
{
- if (mppe_req->stateless)
+ memset(mppe, 0, sizeof(struct pipex_mppe));
+ if (stateless)
mppe->stateless = 1;
- memcpy(mppe->master_key, mppe_req->master_key,
- sizeof(mppe->master_key));
+ if (has_oldkey)
+ mppe->old_session_keys =
+ malloc(PIPEX_MPPE_KEYLEN * PIPEX_MPPE_NOLDKEY,
+ M_TEMP, M_WAITOK);
+ else
+ mppe->old_session_keys = NULL;
+ memcpy(mppe->master_key, master_key, sizeof(mppe->master_key));
- mppe->keylenbits = mppe_req->keylenbits;
- switch (mppe_req->keylenbits) {
+ mppe->keylenbits = keylenbits;
+ switch (keylenbits) {
case 40:
case 56:
mppe->keylen = 8;
@@ -2302,7 +2332,25 @@ pipex_mppe_req_init(struct pipex_mppe_req *mppe_req, struct pipex_mppe *mppe)
GetNewKeyFromSHA(mppe->master_key, mppe->master_key, mppe->keylen,
mppe->session_key);
pipex_mppe_reduce_key(mppe);
- rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen);
+ pipex_mppe_setkey(mppe);
+}
+
+void
+pipex_session_init_mppe_recv(struct pipex_session *session, int stateless,
+ int keylenbits, u_char *master_key)
+{
+ pipex_mppe_init(&session->mppe_recv, stateless, keylenbits,
+ master_key, stateless);
+ session->ppp_flags |= PIPEX_PPP_MPPE_ACCEPTED;
+}
+
+void
+pipex_session_init_mppe_send(struct pipex_session *session, int stateless,
+ int keylenbits, u_char *master_key)
+{
+ pipex_mppe_init(&session->mppe_send, stateless, keylenbits,
+ master_key, 0);
+ session->ppp_flags |= PIPEX_PPP_MPPE_ENABLED;
}
#include <crypto/sha1.h>
@@ -2354,17 +2402,23 @@ Static void
mppe_key_change(struct pipex_mppe *mppe)
{
u_char interim[16];
- struct pipex_mppe keychg; /* just for rc4ctx */
+ struct rc4_ctx keychg;
memset(&keychg, 0, sizeof(keychg));
GetNewKeyFromSHA(mppe->master_key, mppe->session_key, mppe->keylen,
interim);
- rc4_keysetup(&keychg.rc4ctx, interim, mppe->keylen);
- rc4_crypt(&keychg.rc4ctx, interim, mppe->session_key, mppe->keylen);
+ rc4_keysetup(&keychg, interim, mppe->keylen);
+ rc4_crypt(&keychg, interim, mppe->session_key, mppe->keylen);
pipex_mppe_reduce_key(mppe);
+
+ if (mppe->old_session_keys) {
+ int idx = mppe->coher_cnt & PIPEX_MPPE_OLDKEYMASK;
+ memcpy(mppe->old_session_keys[idx],
+ mppe->session_key, PIPEX_MPPE_KEYLEN);
+ }
}
Static void
@@ -2375,6 +2429,7 @@ pipex_mppe_input(struct mbuf *m0, struct pipex_session *session)
uint16_t coher_cnt;
struct mbuf *m1;
u_char *cp;
+ int rewind = 0;
/* pullup */
PIPEX_PULLUP(m0, sizeof(coher_cnt));
@@ -2403,7 +2458,6 @@ pipex_mppe_input(struct mbuf *m0, struct pipex_session *session)
/* adjust mbuf */
m_adj(m0, sizeof(coher_cnt));
-#ifdef WORKAROUND_OUT_OF_SEQUENCE_PPP_FRAMING
/*
* L2TP data session may be used without sequencing, PPP frames may
* arrive in disorder. The 'coherency counter' of MPPE detects such
@@ -2421,22 +2475,29 @@ pipex_mppe_input(struct mbuf *m0, struct pipex_session *session)
if (coher_cnt < mppe->coher_cnt)
coher_cnt0 += 0x1000;
if (coher_cnt0 - mppe->coher_cnt > 0x0f00) {
- pipex_session_log(session, LOG_DEBUG,
- "Workaround the out-of-sequence PPP framing problem: "
- "%d => %d", mppe->coher_cnt, coher_cnt);
- goto drop;
+ if (!mppe->stateless ||
+ coher_cnt0 - mppe->coher_cnt
+ <= 0x1000 - PIPEX_MPPE_NOLDKEY) {
+ pipex_session_log(session, LOG_DEBUG,
+ "Workaround the out-of-sequence PPP framing problem: "
+ "%d => %d", mppe->coher_cnt, coher_cnt);
+ goto drop;
+ }
+ rewind = 1;
}
}
-#endif
+
if (mppe->stateless != 0) {
- mppe_key_change(mppe);
- while (mppe->coher_cnt != coher_cnt) {
+ if (!rewind) {
mppe_key_change(mppe);
- mppe->coher_cnt++;
- mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK;
- pktloss++;
+ while (mppe->coher_cnt != coher_cnt) {
+ mppe->coher_cnt++;
+ mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK;
+ mppe_key_change(mppe);
+ pktloss++;
+ }
}
- flushed = 1;
+ pipex_mppe_setoldkey(mppe, coher_cnt);
} else {
if (flushed) {
if (coher_cnt < mppe->coher_cnt) {
@@ -2461,26 +2522,27 @@ pipex_mppe_input(struct mbuf *m0, struct pipex_session *session)
mppe_key_change(mppe);
flushed = 1;
}
+ if (flushed)
+ pipex_mppe_setkey(mppe);
}
-#ifndef WORKAROUND_OUT_OF_SEQUENCE_PPP_FRAMING
+
if (pktloss > 1000) {
pipex_session_log(session, LOG_DEBUG,
"%d packets loss.", pktloss);
}
-#endif
- if (flushed)
- rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen);
/* decrypt ppp payload */
for (m1 = m0; m1; m1 = m1->m_next) {
cp = mtod(m1, u_char *);
len = m1->m_len;
- rc4_crypt(&mppe->rc4ctx, cp, cp, len);
+ pipex_mppe_crypt(mppe, len, cp, cp);
}
- /* update coher_cnt */
- mppe->coher_cnt++;
- mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK;
+ if (!rewind) {
+ /* update coher_cnt */
+ mppe->coher_cnt++;
+ mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK;
+ }
pipex_ppp_input(m0, session, 1);
@@ -2547,7 +2609,7 @@ pipex_mppe_output(struct mbuf *m0, struct pipex_session *session,
}
if (flushed)
- rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen);
+ pipex_mppe_setkey(mppe);
PIPEX_MPPE_DBG((session, LOG_DEBUG, "out coher_cnt=%03x %s%s",
mppe->coher_cnt, (flushed) ? "[flushed]" : "",
@@ -2572,7 +2634,7 @@ pipex_mppe_output(struct mbuf *m0, struct pipex_session *session,
len -= offsetof(struct mppe_header, protocol);
cp += offsetof(struct mppe_header, protocol);
}
- rc4_crypt(&mppe->rc4ctx, cp, cp, len);
+ pipex_mppe_crypt(mppe, len, cp, cp);
}
pipex_ppp_output(m0, session, PPP_COMP);
@@ -2939,7 +3001,35 @@ pipex_sockaddr_compar_addr(struct sockaddr *a, struct sockaddr *b)
sizeof(struct in6_addr));
}
panic("pipex_sockaddr_compar_addr: unknown address family");
- return -1;
+
+ return (-1);
+}
+
+Static inline int
+pipex_mppe_setkey(struct pipex_mppe *mppe)
+{
+ rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen);
+
+ return (0);
+}
+
+Static inline int
+pipex_mppe_setoldkey(struct pipex_mppe *mppe, uint16_t coher_cnt)
+{
+ KASSERT(mppe->old_session_keys != NULL);
+
+ rc4_keysetup(&mppe->rc4ctx,
+ mppe->old_session_keys[coher_cnt & PIPEX_MPPE_OLDKEYMASK],
+ mppe->keylen);
+
+ return (0);
+}
+
+Static inline void
+pipex_mppe_crypt(struct pipex_mppe *mppe, int len, u_char *indata,
+ u_char *outdata)
+{
+ rc4_crypt(&mppe->rc4ctx, indata, outdata, len);
}
int
diff --git a/sys/net/pipex.h b/sys/net/pipex.h
index 391e69ea54d..cddbbefc893 100644
--- a/sys/net/pipex.h
+++ b/sys/net/pipex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pipex.h,v 1.9 2011/07/08 18:30:17 yasuoka Exp $ */
+/* $OpenBSD: pipex.h,v 1.10 2011/10/15 03:24:11 yasuoka Exp $ */
/*
* Copyright (c) 2009 Internet Initiative Japan Inc.
@@ -216,6 +216,11 @@ struct pipex_session *pipex_l2tp_userland_lookup_session_ipv4 (struct mbuf *, s
struct pipex_session *pipex_l2tp_userland_lookup_session_ipv6 (struct mbuf *, struct in6_addr);
struct mbuf *pipex_l2tp_userland_output (struct mbuf *, struct pipex_session *);
int pipex_ioctl (struct pipex_iface_context *, int, caddr_t);
+void pipex_session_init_mppe_recv(struct pipex_session *, int,
+int, u_char *);
+void pipex_session_init_mppe_send(struct pipex_session *, int,
+int, u_char *);
+
__END_DECLS
#endif /* _KERNEL */
diff --git a/sys/net/pipex_local.h b/sys/net/pipex_local.h
index 11be4715ec8..dcbf9c1ef35 100644
--- a/sys/net/pipex_local.h
+++ b/sys/net/pipex_local.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pipex_local.h,v 1.12 2011/07/08 19:34:04 yasuoka Exp $ */
+/* $OpenBSD: pipex_local.h,v 1.13 2011/10/15 03:24:11 yasuoka Exp $ */
/*
* Copyright (c) 2009 Internet Initiative Japan Inc.
@@ -37,6 +37,8 @@
#define PIPEX_PPPOE 1
#define PIPEX_MPPE 1
+#define PIPEX_REWIND_LIMIT 64
+
#define PIPEX_ENABLED 0x0001
#ifndef LOG_PPPAC
@@ -59,6 +61,9 @@
#define NNBY 8 /* number of bits of a byte */
#endif
+#define PIPEX_MPPE_NOLDKEY 64 /* should be power of two */
+#define PIPEX_MPPE_OLDKEYMASK (PIPEX_MPPE_NOLDKEY - 1)
+
#ifdef PIPEX_MPPE
/* mppe rc4 key */
struct pipex_mppe {
@@ -71,6 +76,7 @@ struct pipex_mppe {
struct rc4_ctx rc4ctx;
u_char master_key[PIPEX_MPPE_KEYLEN]; /* master key of MPPE */
u_char session_key[PIPEX_MPPE_KEYLEN]; /* session key of MPPE */
+ u_char (*old_session_keys)[PIPEX_MPPE_KEYLEN]; /* old session keys */
};
#endif /* PIPEX_MPPE */
@@ -402,7 +408,7 @@ Static struct pipex_session *pipex_l2tp_userland_lookup_session(struct mbuf *,
#endif
#ifdef PIPEX_MPPE
-Static void pipex_mppe_req_init (struct pipex_mppe_req *, struct pipex_mppe *);
+Static void pipex_mppe_init (struct pipex_mppe *, int, int, u_char *, int);
Static void GetNewKeyFromSHA (u_char *, u_char *, int, u_char *);
Static void pipex_mppe_reduce_key (struct pipex_mppe *);
Static void mppe_key_change (struct pipex_mppe *);
@@ -410,8 +416,9 @@ Static void pipex_mppe_input (struct mbuf *, struct pipex_sessi
Static void pipex_mppe_output (struct mbuf *, struct pipex_session *, uint16_t);
Static void pipex_ccp_input (struct mbuf *, struct pipex_session *);
Static int pipex_ccp_output (struct pipex_session *, int, int);
-Static inline int rc4_key(struct pipex_mppe *, int, u_char *);
-Static inline void rc4(struct pipex_mppe *, int, u_char *, u_char *);
+Static inline int pipex_mppe_setkey(struct pipex_mppe *);
+Static inline int pipex_mppe_setoldkey(struct pipex_mppe *, uint16_t);
+Static inline void pipex_mppe_crypt(struct pipex_mppe *, int, u_char *, u_char *);
#endif
Static struct mbuf *adjust_tcp_mss (struct mbuf *, int);